仅在调用write()函数时才能检测到未插入的以太网电缆 . 这是因为tcp堆栈的tcp重传没有你的意识 . 这是解决方案 .
即使您已经为应用程序套接字设置了keepalive选项,但是如果您的应用程序一直在套接字上写入,您无法及时检测到套接字的死连接状态 . 那是因为内核tcp堆栈的tcp重传 . tcp_retries1和tcp_retries2是用于配置tcp重传超时的内核参数 . 很难预测重传超时的精确时间,因为它是由RTT机制计算的 . 你可以在rfc793中看到这个计算 . (3.7 . 数据通信)
每个平台都具有用于tcp重传的内核配置 .
Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4)
HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval
AIX : rto_low, rto_high, rto_length, rto_limit
如果要提前检测死连接,则应为tcp_retries2(默认值为15)设置较低的值,但它仅为单个套接字设置这些值 . 那些是全局内核参数 . 有一些尝试为单个套接字应用tcp重新传输套接字选项(http://patchwork.ozlabs.org/patch/55236/),但我没有在系统头文件中找到这些选项定义 .
作为参考,您可以通过'netstat --timers'监控您的keepalive套接字选项,如下所示 . https://stackoverflow.com/questions/34914278
netstat -c --timer | grep "192.0.0.1:43245 192.0.68.1:49742"
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (1.92/0/0)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (0.71/0/0)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (9.46/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (8.30/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (7.14/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (5.98/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (4.82/0/1)
此外,当keepalive超时时,您可以根据您使用的平台遇到不同的返回事件,因此您不能仅通过返回事件来确定死连接状态 . 例如,当发生keepalive超时时,HP返回POLLERR事件,AIX仅返回POLLIN事件 . 那时您将在recv()调用中遇到ETIMEDOUT错误 .
在最近的内核版本(自2.6.37)中,您可以使用TCP_USER_TIMEOUT选项将运行良好 . 此选项可用于单个插槽 .
最后,您可以使用带有MSG_PEEK标志的read函数,它可以让您检查套接字是否正常 . (MSG_PEEK只是看看数据是否到达内核堆栈缓冲区并且从不将数据复制到用户缓冲区 . )因此,您可以使用此标志仅用于检查套接字是否正常,没有任何副作用 .