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

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

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

最佳答案

实际上,从规范中并不能完全看出这一点,但是对于poll(),它的工作方式如下:


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


简单的事情是在设置POLLINPOLLHUPPOLLERR中的任何一个时尝试读取。

kqueue()中,可能仅触发一个EVFILT_READ过滤器。手册页中对此进行了描述,应该足够清楚。

请注意,如果您没有启用TCP keepalive(FreeBSD默认启用了它们,而大多数其他操作系统则没有启用),那么如果网络以某种方式中断,等待数据读取可能会永远陷入困境。即使启用了TCP keepalive,也往往需要花费几个小时才能检测到断开的连接。

09-27 03:11