概述
很多应用层协议都有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
协议是有连接、面向流的协议。
所以非常容易理解,使用UDP
协议的客户端(例如早期的“OICQ
”)需要定时向服务器发送心跳包,告诉服务器自己在线。
然而,MSN和现在的QQ往往使用的是TCP
连接了,尽管TCP/IP
底层提供了可选的KeepAlive
(ACK-ACK
包)机制,但是它们也还是实现了更高层的心跳包。似乎既浪费流量又浪费CPU,有点莫名其妙。
具体查了下,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://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO ,包括了KeepAlive
的介绍、相关内核参数、C编程接口、如何为现有应用(可以或者不可以修改源码的)启用KeepAlive
机制,很值得详读。
这篇文章的2.4节说的是“Preventing disconnection due to network inactivity
”,阻止因网络连接不活跃(长时间没有数据包)而导致的连接中断,说的是,很多网络设备,尤其是NAT
路由器,由于其硬件的限制(例如内存、CPU处理能力),无法保持其上的所有连接,因此在必要的时候,会在连接池中选择一些不活跃的连接踢掉。典型做法是LRU,把最久没有数据的连接给T掉。通过使用TCP
的KeepAlive
机制(修改那个time
参数),可以让连接每隔一小段时间就产生一些ack
包,以降低被T
掉的风险,当然,这样的代价是额外的网络和CPU负担。
前面说到,许多IM
协议实现了自己的心跳机制,而不是直接依赖于底层的机制,不知道真正的原因是什么。就我看来,一些简单的协议,直接使用底层机制就可以了,对上层完全透明,降低了开发难度,不用管理连接对应的状态。而那些自己实现心跳机制的协议,应该是期望通过发送心跳包的同时来传输一些数据,这样服务端可以获知更多的状态。例如某些客户端很喜欢收集用户的信息……反正是要发个包,不如再塞点数据,否则包头又浪费了……
最后
以上就是悲凉荔枝为你收集整理的TCP协议的KeepAlive机制与HeartBeat心跳包的全部内容,希望文章能够帮你解决TCP协议的KeepAlive机制与HeartBeat心跳包所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复