考虑下这种场景,一个TCP连接已经建立,但是双方没有数据交互,这样的话,不管这两个host之间的路由器奔溃,或者网线断掉,只要两个host没有被重启,这个连接依然保持。这样的话浪费不必要的带宽,成本会增加。其实TCP协议中有一个keepalive定时器。
如果一个连接长时间没有任何动作,那么服务器就会发送一个探查报文段给客户端。然后客户端有以下四种反馈:
1、客户端返回正常的ACK,则服务器知道客户主机是存活的,keepalive定时器两个小时后复位。如果在这两小时计时到期之前,这个连接上有数据交互,则复位保活定时器,为接下来的2小时准备;
2、客户主机已经崩溃,并且关闭或者正在重新启动。服务器不能收到探查响应,默认75秒后超时。服务器总共发送10个探查包,每隔75秒一次,如果一个响应都没有收到,则终止连接;
3、客户主机崩溃并且已经重新启动。服务器收到探查响应,此响应只是一个复位,服务器收到后终止这个连接;
4、客户主机正常运行,但是服务器不可到达,这种情况与2类似。
Linux下keepalive选项默认是关闭的,在编写Socket程序的时候打开keepalive选项如下操作:
int keepAlive = 1; // 开启keepalive属性. 缺省值: 0(关闭)在Linux系统配置中的位置如下:
int keepIdle = 60; // 如果在60秒内没有任何数据交互,则进行探测. 缺省值:7200 s
int keepInterval = 5;// 探测时发探测包的时间间隔为5秒. 缺省值:75 s
int keepCount = 2; // 探测重试的次数. 全部超时则认定连接失效..缺省值:10次
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
setsockopt(s, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
setsockopt(s, SOL_TCP, TCP_KEEPINTVL, (void*)&keepInterval, sizeof(keepInterval));
setsockopt(s, SOL_TCP, TCP_KEEPCNT, (void*)&keepCount, sizeof(keepCount));
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_intvl
/proc/sys/net/ipv4/tcp_keepalive_probes