问题和解决思路
建立tcp连接后,双方互相发送信息,但是可能存在的情况是双方在处理数据,暂时并不会互相发送数据,那么这个时候如何判断双方连接是否依然正常,而没有意外断开呢?或者说假如出现了意外断开,那么导致的后果是长时间的积累会导致非常多的半打开连接,造成端系统资源的消耗和浪费,且有可能导致在一个无效的数据链路层面发送业务数据,结果就是发送失败。因此,我们必须避免这种情况。
一种有效的方法是如果长时间不进行通信,当达到某个时间阈值a时,双方互相发送探测包,同时开启一个定时器。接收到探测包的一方必须进行回复,这用来判断连接是否依然保持存活状态,这就是Tcp心跳包。如果对方回复了ACK,说明连接正常;如果对方回复了RST,说明连接状态丢失;如果一直没有回复,就需要间隔b时间再次发送一次探测包,如果发送c次依然没有回复,说明连接被断开了。
详细内容
上文中的a,b,c就是keep-alive机制中的三个参数,我们可以根据自己的需求设置。但必须注意设置需要合理,比如如果发送次数太少,则可能出现因为网络暂时的波动而导致断开一个健康的tcp连接。需要说明的是,keep-alive机制默认是关闭的,因为其需要消耗额外的宽带和流量,我们可以用setsockopt将SOL_SOCKET.SO_KEEPALIVE设置为1才是打开。
缺陷分析
思考:tcp的keep-alive存在的缺陷?它的作用是监测连接是否依然存活,但是尽管连接可能存活,依然可能存在这样一种情况:tcp连接是正常的,但是对方(服务器)由于负载过高,导致无法响应请求,或者进程死锁了,阻塞了,那么这时keep-alive就没法解决了。说白了,就是说keep-alive只能知道对方还在和你连着,但不知道对方能否正常工作(服务是否可用)。并且,上文表述中暗含的意思是双方长时间不进行通信才会发送心跳包,所以如果通信过程中一方突然断开连接,那么另一方没有收到ack就需要进行多次重传,这时并不会触发keep-alive机制,达不到及时性失效检测的效果。
因此,我们还需要在应用层加入心跳包机制,进行更高级别的判断对端服务是否可用的功能。