我使用TCP Keep-Alive选项来检测死连接。它与使用读取套接字的连接一起工作良好:
setsockopt(mysock,...) // set various keep alive options epoll_ctl(ep,mysock,{EPOLLIN|EPOLERR|EPOLLHUP},) epoll_wait -> (exits after several seconds when remove host disconnects cable)
Epoll等待通过套接字上的EPOLLIN | EPOLLHUP退出而没有问题。
但是,如果我尝试向套接字写很多东西,直到得到EAGAIN,然后轮询读写,则在断开电缆连接时不会出现错误:
setsockopt(mysock,...) // set various keep alive options while(send() != EAGAIN) ; epoll_ctl(ep,mysock,{EPOLLIN|EPOLLOUT|EPOLERR|EPOLLHUP},) epoll_wait -> --- Never exits!!!! even when the cable of the remove host is disconnected!!!
编辑: 附加信息
当我使用wireshark监视通信时,在第一种情况下(阅读中),我每隔几秒钟收到一次确认请求。但是在第二种情况下,我根本没有检测到它们。
如果在传输所有数据之前拔出网络连接,则该连接不会空闲,因此在某些实现中,保持活动计时器不会启动。(请记住,keepalive不是TCP规范的一部分,因此它的实现方式根本不一致。)通常,由于指数补偿和大量重试(tcp_retries2默认为15)的组合,它可能会占用在Keepalive计时器启动之前,传输需要30分钟才能重试超时。
tcp_retries2
解决方法(如果有)取决于您所使用的特定TCP实现。一些较新版本的Linux(2011年1月4日发布的内核版本2.6.37)实现了TCP_USER_TIMEOUT。
通常的建议是在应用程序级别实现通信超时,而不是始终使用基于TCP的keepalive。参见例如HTTP Keep- Alive。