【问题标题】:How could a recv() call block when epoll has signalled activity?当 epoll 发出活动信号时,recv() 调用如何阻塞?
【发布时间】:2017-01-29 10:06:07
【问题描述】:

我的应用程序类似于 libevent,使用 epoll(在级别触发模式下)检测 I/O 活动并调用回调来处理它。

我最近发现我的 TCP/IP 套接字正在阻塞,这是一个意外,但我仍然不希望 recv() 调用阻塞一个 FD,它被 epoll 报告为有读取活动未决.即使套接字出现错误,recv() 肯定会返回并告诉我。

我对此有什么误解?
在这种情况下,什么样的网络状况会导致recv() 阻塞?

【问题讨论】:

  • 您是否将MSG_WAITALL 传递给recv()?在这种情况下,该函数可能会阻塞,即使某些(但不是全部)字节可能已经可用。
  • @RalphTandetzky:没有。recv(fd, buf, BUFSIZE, 0);
  • 这通常是因为 epoll+recv 不是原子的,所以如果 epoll 和 recv 之间发生了其他事情,那么在你调用 recv 时,套接字可能不再准备好读取。但是,如果没有MVCE,就不可能说出您的情况会发生什么。
  • @ChrisDodd:我很想知道可能是什么“东西”。一个套接字怎么能在某一刻准备好,然后在没有错误条件的情况下没有准备好?至于 MCVE,我再也无法重现这个场景了 :( 因此我问的是 epoll/recv 不是一段代码。
  • 如果有多个线程从套接字读取,就会发生这种情况。

标签: c++ linux networking tcp-ip epoll


【解决方案1】:

来自 Linux select 手册页:

在 Linux 下,select() 可能会将套接字文件描述符报告为“准备就绪” 用于阅读”,而随后的读取块。这 例如,可能在数据到达但经过检查时发生 校验和错误并被丢弃。可能还有其他 文件描述符被虚假报告为的情况 准备好。因此,在应该的套接字上使用 O_NONBLOCK 可能更安全 不阻塞。

(是的,我知道 epoll() 与 select() 不同,但我怀疑相同的基本条件适用于两者)

我认为如果你真的想避免阻塞,唯一安全的方法就是将你的套接字设置为非阻塞模式。

【讨论】:

  • 啊哈——大概就是这样。谢谢:)
  • 他们真的应该在手册页中记录这一点,就像select 一样。事实上,我发现这个问题的唯一原因是我阅读了select 的手册页中的注释,想知道epoll 是否也是如此。
【解决方案2】:

如果你使用 Epoll 来轮询 EPOLLIN 事件,那么之后的 recv 调用应该立即返回。此外,我希望您正在使用非阻塞套接字。如果您想查找错误,则可以查找 EPOLLERR 事件。如果套接字在 epoll 信号后关闭,那么 recv 应该会失败。您的 epoll_wait、epoll_ctl 和 socket 创建的代码 sn-p 将有助于调试问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多