【问题标题】:Errno 35 (EAGAIN) returned on recv call在 recv 调用上返回 Errno 35 (EAGAIN)
【发布时间】:2020-02-22 02:13:05
【问题描述】:

我有一个套接字,它等待接收,然后在接收到数据后,向前发送数据进行处理。但是,它再次执行 recv,这一次它什么也没收到,返回 -1,当打印 errno 时,它打印 35(即EAGAIN)。

这只发生在 MAC OS Lion 操作系统上,对于其他操作系统,它运行得非常好

do{
 rc = recv(i, buffer, sizeof(buffer), 0);
 if (rc < 0){
      printf("err code %d", errno); 
 }
 if(rc == 0){ 
      //Code for processing the data in buffer 
      break; 
 } 
      ....
}while(1);

编辑:更正缩进和错误码

【问题讨论】:

  • ESRCHrecv() 调用的不寻常错误。这是一个普通的网络(例如IP)套接字还是带有“特殊”协议的套接字,如netlink。另外,请注意您的缩进。虽然不是这样,但您的 if(rc == 0){ ... } 块似乎在 if (rc &lt; 0){ ... } 块内,这不可能工作。
  • @Celada - 很抱歉应该是 errno 35,抱歉打错了...
  • 无论错误代码是什么,如果可以,请发布错误的名称而不是数字代码。你标记了你的问题osx,所以我在 MacOS 上查找数值,35 是EAGAIN,但它不一定在每个操作系统上都相同。但是这些名称(总的来说)在操作系统中具有相同的含义。通过给出错误的名称,您将使一些无法访问 MacOS 系统的人能够帮助您,以便他们自己发现。
  • EGAIN 表示内核没有数据可以提供给您的接收缓冲区。在发布recv() 之前对您的套接字文件描述符执行select() 调用怎么样?
  • 你是否将套接字设置为非阻塞模式?

标签: c macos sockets


【解决方案1】:

您可以将套接字设置为非阻塞模式或启用接收超时。这是来自 Mac 上的recv(2)

如果出现以下情况,调用将失败:

[EAGAIN] 套接字被标记为非阻塞,接收操作会阻塞,或者设置了接收超时,在接收到数据之前超时。

编辑0:

嗯,抱歉再次引用。这次来自intro(2)

11 EDEADLK 避免了资源死锁。试图 锁定可能导致死锁的系统资源 情况。

...

35 EAGAIN 临时资源 不可用。这是暂时的情况,稍后会调用 相同的例程可以正常完成。

只需使用strerror(3) 找出实际问题。

【讨论】:

  • 感谢您的评论,但是它返回的错误是 EDEADLK。正如之前的评论中所说,我的调用代码没有睡觉。关于为什么这只发生在 Mac OS Lion 而不是 Snow Leopard 的任何想法?
  • 要补充的更多点是,首先在缓冲区中正确获取数据,对其进行处理,然后由于它是一个 while 循环,它再次返回到 recv 并出现错误 errno 35 - 现在它令人困惑对我来说,因为当你说 EAGAIN 时它指向我 EDEADLK...
  • 我决定在这种情况下忽略这个错误继续程序的流程
  • 然后你会忙着循环直到你收到数据——在大多数情况下这不是最好的决定。
  • 所以,现在对所有人来说都是一个悬而未决的问题,我暂时忽略了该错误,开始工作。这个问题我该怎么办?哪个答案要标注?我看过很多 stackoverflow 帖子,其中用户没有标记正确的答案,导致混淆,我不想添加到...打开公平的建议。
【解决方案2】:

您的套接字处于非阻塞模式。 EAGAIN 是当没有数据可供读取时从recv()(和其他系统调用)的正常返回。从这个意义上说,这并不是一个真正的错误。

如果您意味着您的套接字是非阻塞的,那么您需要监视它以找出它何时有可用数据,并且只有在有可用数据时才调用recv()。使用poll()(或kqueue,这是FreeBSD 和MacOS 特有的)来监控is。通常这是在应用程序的主事件循环中完成的。

如果您不是说您的套接字是非阻塞的,那么您应该使用fcntl() 将其设置为阻塞更多:

flags = fcntl(i, F_GETFL, 0); /* add error checking here, please */
flags &= ~O_NONBLOCK;
fcntl(i, F_SETFL, flags); /* add more error checking here! */

但是你应该知道套接字(和所有文件描述符)的默认阻塞状态是阻塞,所以如果你的套接字处于非阻塞模式,那么这意味着有人或某事手动使其成为非阻塞.

在阻塞模式下,recv 调用将阻塞并等待更多数据,而不是返回EAGAIN(或EWOULDBLOCK,与EAGAIN 相同)。

【讨论】:

  • 阻塞模式是默认的。如果他的意思不是非阻塞,他应该删除设置它的代码,而不是添加更多代码来取消它。
  • 感谢 Celada 的评论,但是错误 35 将我指向 EDEADLK 而不是 EAGAIN,在我的情况下是 41?错误代码是否有些不匹配?
  • @EJP 是的。我从这个角度考虑文件描述符可能来自某种总是返回非阻塞套接字的库。这可以解释你的套接字如何在你不知道的情况下是非阻塞的。牵强,我知道。无论如何,OP 已经澄清它是故意非阻塞的
  • 我知道我在这里听起来很疯狂,难道 errno 依赖于操作系统吗?由于在 MAC OS Snow Leopard 中,此代码运行良好,没有任何问题,而且它是唯一出现此问题的 Lion。只是一个疯狂的猜测,如果这真的是疯狂的评论,你可以打败我......
  • 你是对的@Celada,它确实指向 MAC OS Snow Leopard 中的 EAGAIN
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-10
  • 2020-01-08
  • 1970-01-01
  • 2019-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多