检测TCP非正常断开连接 SO_KEEPALIVE 使用缺陷分析 .

目前手头有个关于心博功能的一个案例, 在使用SOL_SOCKET, SO_KEEPALIVE上有一点心得,想写出来和大家分享一下。

关于SOL_SOCKET选项SO_KEEPALIVE有一个很详细的英文How TO, 在下面的网页中大家可以看到详细的内容
http://www.icewalkers.com/Linux/Howto/TCP-Keepalive-HOWTO/index.html

在《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连接是否依然存在。

keepAlive = 1;
Setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));


如果我们不能接受如此之长的等待时间,从TCP-Keepalive-HOWTO上可以知道一共有两种方式可以设置,一种是修改内核关于网络方面的配置参数,另外一种就是SOL_TCP字段的TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT三个选项。


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).

/*开始首次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选项的套接口端检测到数据发送或者数据接受就认为是数据交换。

关闭心跳机制 在性能分析的时候 尤其是分布式系统:云化时候 
      比如,在LAN中进行通信的分布式系统,由于网络延迟和意外掉线的几率微乎其微,所以,可以考虑关闭心跳机制。再比如,当我们断点调试客户端程序时,由于断点时间太久,服务端会判断为客户端已经心跳超时掉线了,在这种情况下,也可以关闭心跳机制。那么如何关闭心跳机制了?可以这样做:
 将RapidPassiveEngine的HeartBeatSpanInSecs属性设置为0。这样客户端就不会发送定时的心跳消息了。
 将RapidServerEngine的HeartbeatTimeoutInSecs属性设置为小于等于0。这表示服务端将不再做心跳超时检查


应用1 

记得以前开发手机游戏时,索爱有一款手机有强制要求,客户端如果超过三分钟无消息发向网络服务端,则会在客户端自动地强制把socket关断。因为socket长连接相对于手机这样资源少的设备来说是宝贵的资源。  (这个强制是指客户端系统自动关的,不是我们代码close的) 
2

在双方TCP套接字建立连接后(即都进入ESTABLISHED状态)并且在两个小时左右上层没有任何数据传输的情况下,这套机制才会被激活。

很多人认为两个小时的时间设置得很不合理。为什么不设置成为10分钟,或者更短的时间?(可以通过SO_KEEPALIVE选项设置。)但是这样做其实并不被推荐。实际上这套机制只是操作系统底层使用的一个被动机制,原理上不应该被上层应用层使用。当系统关闭一个由KEEPALIVE机制检查出来的死连接时,是不会主动通知上层应用的,只有在调用相应的IO操作在返回值中检查出来。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
net.ipv4.tcp_keepalive_time、net.ipv4.tcp_keepalive_intvl和net.ipv4.tcp_keepalive_probes这三个参数都是用于控制TCPkeepalive机制的参数。它们的具体含义如下: 1. net.ipv4.tcp_keepalive_time:该参数定义了TCP keepalive探测报文的发送间隔,单位为秒。当一个TCP连接空闲时间超过该参数设定的值时,内核会发送一个keepalive探测报文给对端。如果对端在一定时间内没有回应,则认为连接已经断开。该参数的默认值为7200秒(2小时)。 2. net.ipv4.tcp_keepalive_intvl:该参数定义了TCP keepalive探测报文的发送间隔,单位为秒。当一次keepalive探测报文未获得对端回应时,内核会继续发送下一次探测报文,直到达到一定次数或连接断开。该参数的默认值为75秒。 3. net.ipv4.tcp_keepalive_probes:该参数定义了TCP keepalive探测报文的最大发送次数。当一个TCP连接空闲时间超过net.ipv4.tcp_keepalive_time设定的值时,内核会发送一次keepalive探测报文给对端,如果对端未回应,则继续发送下一次探测报文,直到达到该参数设定的最大次数或连接断开。该参数的默认值为9次。 需要注意的是,这三个参数的取值应该根据具体的应用场景和网络状况进行调整,以达到最佳的效果。一般来说,建议将net.ipv4.tcp_keepalive_time设置为较小的值,如60秒或120秒,将net.ipv4.tcp_keepalive_intvl设置为较小的值,如30秒或60秒,将net.ipv4.tcp_keepalive_probes设置为较小的值,如3次或5次,以提高连接的可靠性。但是,具体取值还需要根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值