闲说HeartBeat心跳包和TCP协议的KeepAlive机制

很多应用层协议都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议。

学过TCP/IP的同学应该都知道,传输层的两个主要协议是UDP和TCP,其中UDP是无连接的、面向packet的,而TCP协议是有连接、面向流的协议。

所以非常容易理解,使用UDP协议的客户端(例如早期的“OICQ”,听说OICQ.com这两天被抢注了来着,好古老的回忆)需要定时向服务器发送心跳包,告诉服务器自己在线。

然而,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协议实现了自己的心跳机制,而不是直接依赖于底层的机制,不知道真正的原因是什么。

就我看来,一些简单的协议,直接使用底层机制就可以了,对上层完全透明,降低了开发难度,不用管理连接对应的状态。而那些自己实现心跳机制的协议,应该是期望通过发送心跳包的同时来传输一些数据,这样服务端可以获知更多的状态。例如某些客户端很喜欢收集用户的信息……反正是要发个包,不如再塞点数据,否则包头又浪费了……

大概就是这样吧,如果有大牛知道真正的原因,还望不吝赐教。

@2012-04-21

p.s. 通过咨询某个做过IM的同事,参考答案应该是,自己实现的心跳机制通用,可以无视底层的UDP或TCP协议。如果只是用TCP协议的话,那么直接使用KeepAlive机制就足够了。

@2015-09-14
补充一下 @Jack的回复:
“心跳除了说明应用程序还活着(进程还在,网络通畅),更重要的是表明应用程序还能正常工作。而 TCP keepalive 有操作系统负责探查,即便进程死锁,或阻塞,操作系统也会如常收发 TCP keepalive 消息。对方无法得知这一异常。摘自《Linux 多线程服务端编程》”

1.KeepAlive机制很多情况无法检测出来,如网络连接被软件禁用等,不够可靠,网络状态复杂的情况下这种情况尤其严重。2.自己实现心跳可以加入更灵活与实用的机制,比如少了一个心跳,可以马上再次检查,检查间隔递减,这样可以更快的感知网络状态,而不是等待固定的时间。

--

转载请注明出自 http://www.felix021.com/blog/read.php?2076 ,如是转载文则注明原出处,谢谢:)

时间: 2024-10-16 00:51:53

闲说HeartBeat心跳包和TCP协议的KeepAlive机制的相关文章

TCP连接探测中的Keepalive和心跳包. 关键字: tcp keepalive, 心跳, 保活

1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 2) 对于非正常断开, 服务器并不能检测到. 为了回收资源, 必须提供一种检测机制. 2. 导致TCP断连的因素 如果网络正常, socket也通过close操作来进行优雅的关闭, 那么一切完美. 可是有很多情况, 比如网线故障, 客户端一侧突然断电或者崩溃等等, 这些情况server并不能正常检测到连接的断开. 3. 保活的两种方式: 1) 应用层面的心跳机制 自定义心跳消息头. 一般客户端主动发送, 服务器接收后进行回

为什么基于TCP的应用需要心跳包(TCP keep-alive原理分析)

TCP keep-alive的三个参数 用man命令,可以查看linux的tcp的参数: man 7 tcp 其中keep-alive相关的参数有三个: tcp_keepalive_intvl (integer; default: 75; since Linux 2.4) The number of seconds between TCP keep-alive probes. tcp_keepalive_probes (integer; default: 9; since Linux 2.2)

scoket模块 粘包问题 tcp协议特点

scoket()模块函数用法 import socket socket.socket(socket_family,socket_type,protocal=0) 获取tcp/ip套接字 tcpsock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 获取udp/ip套接字 udpsock =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 服务端套接字函数 s.bind()    绑定(主机,端口号)

心跳包实现的另一种机制

因为工作关系,经常用到心跳包.之前是在服务端中的连接的实体中保持一个timer,每秒加一,每次服务端接到客户端的心跳,就会把计数置为0. 当累加到20秒的时候,服务端会接到客户端抛出的掉线函数回调,就会视为客户端掉线,然后从缓存中删掉掉线用户. 实际测试结果表明,这种判断掉线的方式非常靠谱.7*24小时运行不会出现任何异常.但是每个实体保持一个timer,服务器的开销太大了. 所以这里我想到一种方式,就是在实体中包含一个 DateTime LastReceiveHeartBeatTime字段,每

Tcp协议的keepalive功能

L:128 原文地址:https://www.cnblogs.com/jackey2015/p/10643463.html

心跳包(HeartBeat)

http://itindex.net/detail/52922-%E5%BF%83%E8%B7%B3-heartbeat-coderzh 几乎所有的网游服务端都有心跳包(HeartBeat或Ping)的设计,在最近开发手游服务端时,也用到了心跳包.思考思考,心跳包是必须的吗?为什么需要心跳包?TCP没有提供断线检测的方法吗?TCP提供的KeepAlive机制可以替代HeartBeat吗? 由于连接丢失时,TCP不会立即通知应用程序.比如说,客户端程序断线了,服务端的TCP连接不会检测到断线,而是

TCP连接探测中的Keepalive 和心跳包

采用TCP连接的C/S模式软件,连接的双方在连接空闲状态时,如果任意一方意外崩溃.当机.网线断开或路由器故障,另一方无法得知TCP连接已经失效,除非继续在此连接上发送数据导致错误返回.很多时候,这不是我们需要的.我们希望服务器端和客户端都能及时有效地检测到连接失效,然后优雅地完成一些清理工作并把错误报告给用户. 如何及时有效地检测到一方的非正常断开,一直有两种技术可以运用.一种是由TCP协议层实现的Keepalive,另一种是由应用层自己实现的心跳包. TCP默认并不开启Keepalive功能,

浅析C#基于TCP协议的SCOKET通信

TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是一天两天的功夫,所幸的是在.net framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序. C#基于TCP协议的网络通讯 要进行C#基于TCP协议的网络通讯,首先必须建立同远程主机的连接,连接地址通常包括两部分--主机名和端口,

TCP协议基础

IP协议是Internet上使用的一个关键协议,它的全称是Internet  Protocol,即Internet协议,通常简称IP协议.通过使用IP协议,使Internet·成为一个允许连接不同类型的计算机和不同操作系统的网络. 要使两台计算机彼此之间进行通信,必须使两台计算机使用同一种“语言”,IP协议只保证计算机能发送和接收分组数据.IP协议负责将消息从一个主机传送到另一个主机,消息在传送的过程中被分割成一个个小包. 尽管计算机通过安装IP软件,保证了计算机之间可以发送和接收数据,但IP协