1. Keep Alive
TCP 保活定时器,Keep Alive,特别强调一下,不是 HTTP 协议里的那个 Keep Alive.
在 HTTP 中,keep alive 是在应用层实现的,目的在于延长连接时间,即应用层服务器如果在一定时间内(通过 keep alive 进行设置)没有和客户端交互,就关闭连接。感兴趣的朋友可以自行 baidu or google.
TCP 中的 Keepalive 是 TCP 本身实现的,和应用层无关。它的目的在于看看对方有没有发生异常。
在 TCP 层面,如果双方没有任何数据交互,这个连接会永远存在,这意味着如果客户与服务器建立连接,可以在数小时,数天甚至数月之后连接依然保持。中间设备(比如路由器)可以崩溃,可以重启,网络可以断,只要两端的主机不重启,都没有关系。
很多时候,一个连接经过了很久都没有数据交互,服务器想知道对方是不是已经崩溃,或者又重新启动了,怎么办呢?TCP 的 Keep Alive,保活定时器就是做这事的。
它每隔一段时间会超时,超时后会检查连接是否空闲太久了,如果空闲的时间超过了设置时间,就会发送探测报文。然后通过对端是否响应、响应是否符合预期,来判断对端是否正常,如果不正常,就主动关闭连接。
有些系统的 TCP 实现中,将 keep alive 设置为 2 小时,所以这个实验我就不做了,,,实在是太久了……
关于 TCP 的 Keep Alive 是一个有争议的功能,许多人认为这个功能不应该在 TCP 中提供,而应该有应用层程序来完成。因为有时候,Keep Alive 可能会让一个非常棒的连接终止掉,比如,链路中间有一台路由器正在重启,此时,Keep Alive 正在发送保活探测报文,导致认为对端主机崩溃,从而终止连接。
2. 细节
这里假设服务器开启了Keep Alive 功能(这个选项在编程时是需要自己主动打开的),客户端没有开启。我们讨论 4 种情况:
- 客户机正常运行,服务器报文可达
服务器和客户机每一次交换数据,都会复位 Keep Alive 定时器。如果 2 小时内没有数据交换,服务器发送探查报文,并在 75 秒后超时(这个值在现代的 Linux 内核上不知道有没有改,不过我们并不关心它,只关心这个流程),服务器收到客户端回应的探查报文后,认为对方正常,重新复位 Keep Alive 定时器。
- 客户机崩溃
2 小时空闲后,服务器发送探查报文,75 秒后超时。服务器会连续发送 10 个这样的探查报文,每次间隔 75 秒。如果服务器一个响应都没收到,就认为客户机已经关闭,于是终止连接。
- 客户机重启
2 小时空闲后,服务器发送探查报文,这时服务器会收到对方回应的 RST 段。因为重启后的客户机根本不知道这个连接。
- 客户机正常运行,但是服务器不可达。
实际上,这个第二种情况“客户机崩溃”没有区别,它们的结果是一样的。因为服务器无法区别这两种情况。
上面所有这一切都是由 TCP 负责的,对应用程序来说,都是透明的。
3. 总结
- keep alive 的作用
- TCP 的 keep alive 是在 tcp 协议栈中实现的
大多数时候,我们写服务器程序的时候,会在应用层实现一个 Keep Alive,而不使用 TCP 提供的,比如常见的 HTTP 协议中就实现了这个功能,还有 SSH 协议也实现了自己的 keep alive 功能。