我知道如果远程主机正常关闭了连接,epoll
将报告EPOLLIN
,并且会调用read
或recv
不阻塞,并将返回0字节(即流的结束)。
但是,如果没有正常关闭连接,并且write
或send
操作失败,这是否会导致epoll
随后为该套接字返回EPOLLIN
,从而生成流场景的相同/类似结束?
我试图找到有关此行为的文档,但没有成功,虽然我可以测试它,但我对使用特定内核版本的特定发行版上发生的情况不感兴趣。
答案 0 :(得分:2)
从规范中确实并不完全明显,但poll()
:
POLLIN
。POLLHUP
或POLLERR
。shutdown(SHUT_WR)
),则会返回POLLIN
,并且不会返回POLLHUP
和POLLERR
。 (这允许正常等待POLLOUT
。)简单的做法是在设置POLLIN
,POLLHUP
和POLLERR
的任何内容时尝试阅读。
在kqueue()
中,只有EVFILT_READ
过滤器可能会被触发。这在手册页中有描述,应该足够清楚。
请注意,如果您不启用TCP keepalive(FreeBSD默认启用它们,但大多数其他操作系统不启用),如果网络以某种方式中断,等待数据读取可能会永远停滞不前。即使启用了TCP Keepalive,也可能需要几个小时才能检测到连接断开。
答案 1 :(得分:-1)
当对等机器意外关闭时,它可能不会返回EPOLLIN。在过去,我通过VirtualBox将这种现象归为以下步骤:
我看到连接仍在服务器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。
但我很好奇为什么你不会在收到写入错误时关闭套接字,为什么你仍然会轮询它。这不是正确的行为。