【问题标题】:Read signaled by select(), but recv() returns no data and signal EAGAIN on non-blocking sockets由 select() 发出读取信号,但 recv() 在非阻塞套接字上不返回数据和信号 EAGAIN
【发布时间】:2011-11-24 11:55:07
【问题描述】:

我已经从 select() 获得了用于读取的信号套接字,但是 recv call() 没有到达数据,而是返回 -1 并带有 errno==EAGAIN。

我可以保证没有其他线程接触套接字。

我认为这种行为是不正确的。如果随后发生来自另一方的关闭,我可以预期 recv 的返回值 0(优雅关闭)或其他错误代码,但不是 EAGAIN,因为我认为这意味着数据将在未来到达。

我找到了一些关于问题here 的先前帖子,但没有解决方案。

这种行为在 Ubuntu Linux Oneric 或其他最后的 Linux 发行版上发生在我身上,然后来自链接发布的信息 here

3.0.0 内核或最新的 2.6.x 内核不会修复它

有人知道为什么会发生这种情况以及如何避免这种不受欢迎的行为吗?

【问题讨论】:

标签: c sockets recv select-function


【解决方案1】:

Select() 将套接字报告为可读并不意味着有内容要读取;这意味着读取不会阻塞。读取可以返回 -1 或 0,但不会阻塞

更新:

select返回可读后:如果read()返回-1,检查errno。 EAGAIN/EWOULDBLOCK 和 EINTR 是需要特别处理的值:主要是通过重新发出 read(),但您可能会相信选择循环会在下一次返回可读。

如果涉及多个线程,事情可能会变得更加困难。

【讨论】:

  • EAGAIN 是当读取被阻塞但您设置了 O_NONBLOCK 时得到的结果。
  • 但这或多或少与 select() 报告的内容正交。 Select 保证后续读取不会阻塞。 (有特殊情况,例如涉及需要 O_NONBLOCK 的 UDP,但这并不重要)
  • 这里的问题是, select() 发出的读取信号是什么意思。因为在这个 read->EAGAIN 之后,我再次调用了 select(),然后这个调用永远不会返回(这里 select 有无限超时)。
  • @Zdendal 在这种情况下,这是您代码中某处的错误(假设确实发生了事件,并且网络中没有丢失数据或关闭信息)
  • 如果 EAGAIN 结果只是偶尔出现,而后续调用 select() 会阻塞,那我不用太担心,你可以忽略它。如果 select() 总是立即返回,然后 recv() 总是返回 -1/EAGAIN,这只是一个真正的问题,导致你的事件循环旋转 CPU。
【解决方案2】:

我遇到了同样的问题,但使用的是 epoll。我注意到,只要系统重用已关闭的套接字的 FD 编号,就会发生这种情况。 经过一些研究,我注意到这种行为是由于在对它们进行 epoll 时关闭套接字引起的。尝试在关闭套接字时避免在套接字上运行 select - 这可能会有所帮助。

【讨论】:

    猜你喜欢
    • 2010-10-29
    • 2010-10-18
    • 2011-09-13
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    相关资源
    最近更新 更多