0

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

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

我试图找到有关此行为的文档,但没有成功,虽然我可以对其进行测试,但我对具有特定内核版本的特定发行版上会发生什么不感兴趣。

4

4 回答 4

2

从规范中确实不是很明显,但它的工作原理如下poll()

  • 如果有数据可供读取,即使连接关闭,POLLIN也会返回。
  • 如果由于连接关闭而无法读取或写入,POLLHUPPOLLERR返回。
  • 如果不再可以读取但可以写入(例如,如果对方做了shutdown(SHUT_WR)),POLLIN则返回并且POLLHUPPOLLERR返回。(这允许正常等待POLLOUT。)

简单的做法是在设置和POLLIN时尝试读取。POLLHUPPOLLERR

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

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

于 2013-11-17T00:43:47.063 回答
-1

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

尽管您必须知道TCP并不完美。如果连接被另一端异常终止(物理链路断开),那么在您写入套接字之前,您的一侧可能永远不会检测到这一点。TCP_KEEPALIVE可能有帮助,但作用不大。

于 2013-11-17T00:10:08.207 回答
-1

当对端机器意外关闭时,它可能不会返回 EPOLLIN。过去,我通过 VirtualBox 遇到过这种现象,步骤如下:

  1. 在一台 VM 上启动服务器。
  2. 在另一个 VM 上启动客户端,连接服务器并保持连接而不做任何事情。
  3. 保存客户端 VM 状态(类似于休眠)。

我看到连接仍然在服务器虚拟机中建立

netstat -anp --tcp 

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

http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/说默认情况下它将保持大约 7200 秒。

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

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

于 2013-10-29T18:15:07.537 回答
-1

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

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

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

于 2013-11-17T02:41:47.323 回答