🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
TCP协议的`KeepAlive`机制与`HeartBeat`心跳包 * HeartBeat心跳包 很多应用层协议都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议。 心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。 在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO\_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。 心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。 其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。 理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。 在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。 总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。 * TCP协议的`KeepAlive`机制 TCP的IP传输层的两个主要协议是UDP和TCP,其中UDP是无连接的、面向packet的,而TCP协议是有连接、面向流的协议。 TCP的`KeepAlive`机制,首先它貌似默认是不打开的,要用`setsockopt`将`SOL_SOCKET.SO_KEEPALIVE`设置为1才是打开,并且可以设置三个参数`tcp_keepalive_time/tcp_keepalive_probes/tcp_keepalive_intvl`,分别表示连接闲置多久开始发`keepalive`的ack包、发几个ack包不回复才当对方死了、两个ack包之间间隔多. 在测试的时候用`Ubuntu Server 10.04`下面默认值是7200秒(2个小时,要不要这么蛋疼啊!)、9次、75秒。 于是连接就了有一个超时时间窗口,如果连接之间没有通信,这个时间窗口会逐渐减小,当它减小到零的时候,TCP协议会向对方发一个带有ACK标志的空数据包(KeepAlive探针),对方在收到ACK包以后,如果连接一切正常,应该回复一个ACK;如果连接出现错误了(例如对方重启了,连接状态丢失),则应当回复一个RST;如果对方没有回复,服务器每隔intvl的时间再发ACK,如果连续probes个包都被无视了,说明连接被断开了。 在http早期,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。 使用`keep-alive`可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用`keep-alive`机制,可以减少tcp连接建立次数,也意味着可以减少`TIME_WAIT`状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的`accept()`和`close()`调用)。 但是,`keep-alive`并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的`keep-alive`,有时比重复利用连接带来的损失还更大。所以,正确地设置`keep-alive timeout`时间非常重要。 使用`http keep-alvie`,可以减少服务端`TIME_WAIT`数量(因为由服务端httpd守护进程主动关闭连接)。道理很简单,相较而言,启用`keep-alive`,建立的tcp连接更少了,自然要被关闭的tcp连接也相应更少了。 使用启用`keepalive`的不同。另外,`http keepalive`是客户端浏览器与服务端httpd守护进程协作的结果,所以,我们另外安排篇幅介绍不同浏览器的各种情况对`keep-alive`的利用。 [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/106.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/106.jpg)