TCP Keepalive 机制
什么是TCP keepalive?
keepalive的概念非常简单:当建立一个TCP连接时,将关联一组计时器。其中一些计时器处理keepalive过程。当keepalive定时器达到0时,你发送给对方一个keepalive探测包,里面没有数据,并且ACK标志打开。可以这样做是因为TCP/IP规范,作为一种重复的ACK,而且远程端点将没有参数,因为TCP是面向流的协议。另一方面,将收到来自远程主机的回复(它根本不需要支持keepalive,只需要TCP/IP),没有数据和ACK设置。
如果收到keepalive探测的应答,则可以断言连接仍在运行,而不必担心用户级实现。事实上,TCP允许您处理流,而不是包,因此零长度的数据包对用户程序没有危险。
这个过程很有用,因为如果其他对等体失去了连接(例如重新启动),您将注意到连接已经断开,即使您没有流量在连接上。如果keepalive探测没有得到对等体的回应,您可以断言该连接不能被认为是有效的,然后采取正确的操作。
为什么要用TCP keepalive
没有keepalive,你也可以很开心的玩耍,所以如果您正在阅读这篇文章,您可能正在尝试理解keepalive是否可以解决你的问题。
Keepalive是非侵入性的,而且在大多数情况下,如果你有疑问,你可以打开它而不会有出错的风险。但请记住,它会产生额外的网络流量,这可能会对路由器和防火墙产生影响。
- 检查对端是否死亡
- 防止由于网络不活跃而断开连接
检查对端是否死亡
当你的对端死亡时,Keepalive可以在它通知你之前通知你。发生这种情况的原因有很多,比如内核panic或处理该对等进程的被终止。当需要keepalive来检测对等体死亡时,另一个场景是当对等体仍然活着,但它与您之间的网络通道发生故障时。在这种情况下,如果网络不能再次运行,则相当于对等死亡。这是一种正常TCP操作对检查连接状态不起作用的情况。
认为一个简单的点和点之间的TCP连接B:最初的三方握手,与一个SYN段从A到B, B SYN / ACK回来一个,最后一个ACK从A到B。在这个时候,我们在一个稳定的状态:建立连接,现在我们通常会等待别人发送数据的通道。问题就来了:拔掉B的电源,它马上就会断开,而不会通过网络发送任何东西来通知A连接即将断开。从A的角度来看,它已经准备好接收数据,并且不知道B已经崩溃。现在将电源恢复到B,等待系统重启。A和B现在又回来了,但是A知道与B的连接仍然处于活动状态,B不知道。当A试图在死连接上向B发送数据,而B回复一个RST包,导致A最终关闭连接时,这种情况就会自行解决。
Keepalive可以告诉你何时对端变得不可达,而不会有误报的风险。事实上,如果问题出现在两个对等体之间的网络中,那么keepalive操作就是等待一段时间,然后重试,在标记连接断开之前发送keepalive包。
_____ _____
| | | |
| A | | B |
|_____| |_____|
^ ^
|--->--->--->-------------- SYN -------------->--->--->---|
|---<---<---<------------ SYN/ACK ------------<---<---<---|
|--->--->--->-------------- ACK -------------->--->--->---|
| |
| system crash ---> X
|
| system restart ---> ^
| |
|--->--->--->-------------- PSH -------------->--->--->---|
|---<---<---<-------------- RST --------------<---<---<---|
| |
防止由于网络不活跃而断开连接
keepalive的另一个有用的目标是防止非活动断开通道。这是一个非常常见的问题,当您在NAT代理或防火墙之后,无缘无故断开连接。此行为是由代理和防火墙中实现的连接跟踪过程引起的,这些过程跟踪通过它们的所有连接。由于这些机器的物理限制,它们只能在内存中保留有限数量的连接。最常见、最符合逻辑的策略是保留最新的连接,首先丢弃旧的、不活跃的连接。
_____ _____ _____
| | | | | |
| A | | NAT | | B |
|_____| |_____| |_____|
^ ^ ^
|--->--->--->---|----------- SYN ------------->--->--->---|
|---<---<---<---|--------- SYN/ACK -----------<---<---<---|
|--->--->--->---|----------- ACK ------------->--->--->---|
| | |
| | <--- connection deleted from table |
| | |
|--->- PSH ->---| <--- invalid connection |
| | |