什么构成“可读”(kqueue / epoll)

时间:2013-10-29 17:54:43

标签: linux unix posix epoll kqueue

我知道如果远程主机正常关闭了连接,epoll将报告EPOLLIN,并且会调用readrecv不阻塞,并将返回0字节(即流的结束)。

但是,如果没有正常关闭连接,并且writesend操作失败,这是否会导致epoll随后为该套接字返回EPOLLIN,从而生成流场景的相同/类似结束?

我试图找到有关此行为的文档,但没有成功,虽然我可以测试它,但我对使用特定内核版本的特定发行版上发生的情况不感兴趣。

4 个答案:

答案 0 :(得分:2)

从规范中确实并不完全明显,但poll()

的工作原理如下
  • 如果有可供阅读的数据,即使连接已关闭,也会返回POLLIN
  • 如果由于关闭连接而无法进行阅读或书写,则会返回POLLHUPPOLLERR
  • 如果不再可以阅读但是写作(例如另一方做shutdown(SHUT_WR)),则会返回POLLIN,并且不会返回POLLHUPPOLLERR。 (这允许正常等待POLLOUT。)

简单的做法是在设置POLLINPOLLHUPPOLLERR的任何内容时尝试阅读。

kqueue()中,只有EVFILT_READ过滤器可能会被触发。这在手册页中有描述,应该足够清楚。

请注意,如果您不启用TCP keepalive(FreeBSD默认启用它们,但大多数其他操作系统不启用),如果网络以某种方式中断,等待数据读取可能会永远停滞不前。即使启用了TCP Keepalive,也可能需要几个小时才能检测到连接断开。

答案 1 :(得分:-1)

当对等机器意外关闭时,它可能不会返回EPOLLIN。在过去,我通过VirtualBox将这种现象归为以下步骤:

  1. 在一台VM上启动服务器。
  2. 在另一台虚拟机上启动客户端,连接服务器并保持连接而不做任何事情。
  3. 保存客户端虚拟机状态(类似于休眠)。
  4. 我看到连接仍在服务器VM中建立

    netstat -anp --tcp 
    

    换句话说,服务器中没有触发EPOLLIN。

    http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/表示默认会保留约7200秒。

    当然,您可以通过setsockopt或内核参数更改保持活动超时值。

    但是有些书说更好的解决方案是在应用层中检测它,例如设计协议,确保定期发送一些虚拟消息以检测连接状态。

答案 2 :(得分:-1)

epoll()基本上是poll(),但是当你增加fds的数量时它会更好地扩展。当你将它用作边缘触发接口时,我不确定它是做什么的。但是对于关卡触发 - 是的,总是返回EPOLLIN,前提是您正在侦听此事件,如果检测到流结束。

虽然你必须知道 TCP 并不完美。如果连接被另一方异常终止(物理链路断开),则在您写入套接字之前,您的一方可能永远不会检测到此情况。 TCP_KEEPALIVE可能有所帮助,但并不多。

答案 3 :(得分:-1)

  

但是,如果没有正常关闭连接,并且写入或发送操作失败,这是否会导致epoll随后返回该套接字的EPOLLIN,从而产生相同/类似的流结束场景?

没有。这意味着收到FIN,这意味着连接正常终止,但没有发生。我希望你会得到一个EPOLLERR或EPOLLHUP。

但我很好奇为什么你不会在收到写入错误时关闭套接字,为什么你仍然会轮询它。这不是正确的行为。