1、TCP保活的必要性
1)我们知道TCP是无感知的虚拟链接,中间断开两端并不会感知到。(注:关于虚拟连接就是说我并不实际感知你的存在,只是因为我存储了你对应的一个结构和状态就认为你实际存在)
2)很多防火墙等会对空闲的socket自动关闭;连接的双方在链接空闲状态时,任意一方意外崩溃、宕机、网线断开、路由器故障等事情都是有可能发生的。
3)对于非正常的断开服务器自身并不能检测到,除非继续在此连接上发送数据导致错误返回,我们才能判断连接出现故障。显然这不是我们真正需要的。
4)我们希望服务端和客户端都能及时有效地检测到连接失败,然后自动的进行一个清理工作并把错误报告给用户。
2、保活的两种方式
1)应用层面的心跳机制
很好理解应用层实现探测。例如自定义心跳消息头客户端主动发送,服务端可回也可不回。这里不细讲。
2)TCP协议自带的保活功能
TCP默认不开启Keepalive功能,因为开启后需要消耗额外的带宽和流量,尽管微不足道。另外Keepalive设置不合理时可能会因为短暂的网络波动而错误的断开健康的TCP链接。
3、类Unix平台设置keep-alive:
前面说了keepalive默认是关闭的,毕竟会产生流量方面的开销,虽然说很小。一次需要用户手动开启,有两种方式
1)代码层面针对单个socket进行单独的设置(没错用到的就是setsockopt)。代码如下,都是这么写的。
int keepAlive = 1; // 开启keepalive属性. 缺省值: 0(关闭)
int keepIdle = 60; // 如果在60秒内没有任何数据交互,则进行探测. 缺省值:7200(s)
int keepInterval = 5; // 探测时发探测包的时间间隔为5秒. 缺省值:75(s)
int keepCount = 2; // 探测重试的次数. 全部超时则认定连接失效..缺省值:9(次)
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));
注:使用时需要#include <netinet/tcp.h>, 否则SOL_TCP和TCP_KEEPIDLE等3个宏找不到.
2)修改配置文件,对整个系统所有的socket生效。
cat命令查看到系统中这几个默认的值.
cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
修改它们:
echo 60 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 5 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes