在《UNIX网络编程第1卷》中也有详细的阐述:编程
SO_KEEPALIVE 保持链接检测对方主机是否崩溃,避免(服务器)永远阻塞于TCP链接的输入。设置该选项后,若是2小时内在此套接口的任一方向都没有数据交换,TCP就自 动给对方 发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.它会致使如下三种状况:对方接收一切正常:以指望的ACK响应。2小时后,TCP将发出另外一个探测分 节。对方已崩溃且已从新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接 口自己则被关闭。对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图获得一个响应。在发出第一个探测分节11分钟 15秒后若仍无响应就放弃。套接口的待处理错误被置为ETIMEOUT,套接口自己则被关闭。如ICMP错误是“host unreachable(主机不可达)”,说明对方主机并无崩溃,可是不可达,这种状况下待处理错误被置为 EHOSTUNREACH。服务器
在该书的第158页有更详细的描述。网络
根据上面的介绍咱们能够知道对端以一种非优雅的方式断开链接的时候,咱们能够设置SO_KEEPALIVE属性使得咱们在2小时之后发现对方的TCP链接是否依然存在。app
keepAlive = 1;
Setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));socket
若是咱们不能接受如此之长的等待时间,从TCP-Keepalive-HOWTO上能够知道一共有两种方式能够设置,一种是修改内核关于网络方面的 配置参数,另一种就是SOL_TCP字段的TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT三个选项。tcp
The tcp_keepidle parameter specifies the interval of inactivity that causes TCP to generate a KEEPALIVE transmission for an application that requests them. tcp_keepidle defaults to 14400 (two hours).ide
/*开始首次KeepAlive探测前的TCP空闭时间 */函数
The tcp_keepintvl parameter specifies the interval between the nine retries that are attempted if a KEEPALIVE transmission is not acknowledged. tcp_keepintvl defaults to 150 (75 seconds).
/* 两次KeepAlive探测间的时间间隔 */继承
The TCP_KEEPCNT option specifies the maximum number of keepalive probes to be sent. The value of TCP_KEEPCNT is an integer value between 1 and n, where n is the value of the systemwide tcp_keepcnt parameter.接口
/* 断定断开前的KeepAlive探测次数 */
所以咱们能够获得
int keepIdle = 6;
int keepInterval = 5;
int keepCount = 3;
Setsockopt(listenfd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
Setsockopt(listenfd, SOL_TCP,TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
Setsockopt(listenfd,SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
咱们须要注意的TCP-Keepalive-HOWTO上这段话:
Remember that keepalive is not program−related, but socket−related, so if you have multiple sockets, you can handle keepalive for each of them separately.
这些属性是sockt继承的,非整个代码内的全部sockets都继承这个属性,由于若是要应用到多个套接口上必须分别使用Setsockopt, Setsockopt是setsockopt的包裹函数。
若是心搏函数要维护客户端的存活,即服务器必须每隔一段时间必须向客户段发送必定的数据,那么使用SO_KEEPALIVE是有很大的不足的。由于 SO_KEEPALIVE选项指"此套接口的任一方向都没有数据交换",我不知道你们是怎么理解这个实现的。在Linux 2.6系列上,上面话的理解是只要打开SO_KEEPALIVE选项的套接口端检测到数据发送或者数据接受就认为是数据交换。
所以在这种状况下使用 SO_KEEPALIVE选项 检测对方是否非正常链接是彻底没有做用的,在每隔一段时间发包的状况, keep-alive的包是不可能被发送的。上层程序在非正常端开的状况下是能够正常发送包到缓冲区的。非正常端开的状况是指服务器没有收到"FIN" 或者 "RST"包。
固然这种状况也是比较好判定对方是否存活,我提出来的主要缘由是想看看你们对"此套接口的任一方向都没有数据交换"是怎么去理解的。