tcp对连接断开的感知——保活定时器

     根据tcp/ip协议的描述,tcp连接建立之后,如果双方没有通信,连接可以一直保存下去,假如中间路由器崩溃或者中间的某条线路断开,只要两端的主机没有被重启,连接就一直被保持着。
     在实际应用中,这是一个很重要的问题:在很多时候服务器与客户端建立tcp连接之后,基于各种异常原因,经常发生客户端还没有来得及向服务器发送断开连接时就崩溃掉了的问题,服务器就需要能够感知这种变化。然而,TCP规范中未规定连接的保活功能,它主要基于以下3个方面的考虑
1)耗费不必要的带宽;
2)在收费的网络上,这个会花掉更多的钱;
3)加入连接只是出现短暂的差错,加入此功能可能会引起一条好的连接被释放掉。

     尽管tcp协议规范中未做次要求,但是在很多tcp协议的实际实现中,却提供了保活定时器的功能。通常情况下,保活功能主要是为服务器程序提供,因为一般情况下,服务器会为一条连接绑定相应的资源,如果这个条连接的另一方突然消失了,服务器方需要感知到这种情况,并把绑定的资源回收回来。

socket选项字段SO_KEEPALIVE用于表示是否设置保活功能,可用函数getsocketopt获取socket的选项信息,用setsocketopt函数设置socket的选项信息,如果socket被设置了SO_KEEPALIVE,那么如果2小时内如果该socket没有传输任何数据时,tcp就自动给对端发送一个保活探测分节,该分节对方必须相应。

     保活定时器一般配置的时间是2小时,即服务器每个2小时就会向客户端发送探查消息,如果收到客户端的反馈消息,则再等2个小时再发;如果等不到客户端的反馈,则再等75秒钟再发一次保活探查,这样连续发送10次,如果10次都没有收到反馈,就认为客户端已经异常断开了,此时,tcp层的程序就会向上层应用程序发送一条“连接超时”的错误反馈。

 注意:

1)在自己模拟测试这种异常断开的情况时,通常采取的措施是直接拔掉网线;而不是关掉程序或杀死进程,例如在linux下直接ctrl+c的方式关掉程序,这种情况下的关闭,会让tcp连接向对方发送一条断开的连接的消息。所以达不到模拟异常断开的测试需要。

2)保活定时器的的时间长度是可以配置的,但是该参数是系统级的参数,一旦改动会对整个系统的所有tcp连接都有影响,因此,尽量不要修改该参数,另外该参数的默认值必须大于或等于2个小时。
     由于tcp的很多实现中,保活定时器的时间比较长(一般都大于2个小时),在实际的服务器程序开发过程中,很难利用该时间来判断客户端是否断开连接。因此,很多服务器程序都在上层自己提供保活功能,也就是服务器程序开发过程中经常提到的:心跳连接或ping/pong消息等功能。
以开源程序mosquitto为例,它为此提供了ping/pong功能,并通过keepalive的参数来控制检查时间,一般客户端需要在keepalive时间内向服务器发送一条消息,表明自己还存在,服务器会周期检查与客户端建立起的每一个连接,如果某个连接在keepalive*1.5的时间内没有收到过消息,则认为这个连接就失效了,于是服务器将主动断开这个超时的连接。

    

你可能感兴趣的:(tcp对连接断开的感知——保活定时器)