为什么基于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)
              The  maximum  number  of  TCP  keep-alive  probes  to send before giving up and killing the connection if no
              response is obtained from the other end.

       tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
              The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes.   Keep-
              alives  are  sent only when the SO_KEEPALIVE socket option is enabled.  The default value is 7200 seconds (2
              hours).  An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval
              of 75 seconds apart) when keep-alive is enabled.

这些的默认配置值在/proc/sys/net/ipv4 目录下可以找到。

可以直接用cat来查看文件的内容,就可以知道配置的值了。
也可以通过sysctl命令来查看和修改:

# 查询
cat /proc/sys/net/ipv4/tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_time
#修改
sysctl net.ipv4.tcp_keepalive_time=3600

上面三个是系统级的配置,在编程时有三个参数对应,可以覆盖掉系统的配置:

TCP_KEEPCNT 覆盖  tcp_keepalive_probes,默认9(次)
TCP_KEEPIDLE 覆盖 tcp_keepalive_time,默认7200(秒)
TCP_KEEPINTVL 覆盖 tcp_keepalive_intvl,默认75(秒)
 ```

## tcp keep-alive的本质
###TCP keep-alive probe
上面了解了tcp keep-alive的一些参数,下面来探究下其本质。

在远程机器192.168.66.123上,用nc启动一个TCP服务器:
```bash
nc -l 9999

<div class="se-preview-section-delimiter"></div>

在本地机器上,用python创建一个socket去连接,并且用wireshark抓包分析

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)

s.connect(('192.168.66.123', 9999))

上面的程序,设置了TCP_KEEPIDLE为20,TCP_KEEPINTVL为1,系统默认的tcp_keepalive_probes是9。

当网络正常,不做干扰时,wireshark抓包的数据是这样的(注意看第二列Time):

可以看到,当3次握手完成之后,每隔20秒之后66.120发送了一个TCP Keep-Alive的数据包,然后66.123回应了一个TCP Keep-Alive ACK包。这个就是TCP keep-alive的实现原理了。

当发送了第一个TCP Keep-Alive包之后,拨掉192.168.66.123的网线,然后数据包是这样子的:

可以看到,当远程服务器192.168.66.123网络失去连接之后,本地机器(192.168.66.120)每隔一秒重发了9次tcp keep-alive probe,最终认为这个TCP连接已经失效,发了一个RST包给192.168.66.123。

在本地机器上,用python创建一个socket去连接,并且用wireshark抓包分析
```python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 20)
s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 1)

s.connect(('192.168.66.123', 9999))

上面的程序,设置了TCP_KEEPIDLE为20,TCP_KEEPINTVL为1,系统默认的tcp_keepalive_probes是9。

当网络正常,不做干扰时,wireshark抓包的数据是这样的(注意看第二列Time):

可以看到,当3次握手完成之后,每隔20秒之后66.120发送了一个TCP Keep-Alive的数据包,然后66.123回应了一个TCP Keep-Alive ACK包。这个就是TCP keep-alive的实现原理了。

当发送了第一个TCP Keep-Alive包之后,拨掉192.168.66.123的网线,然后数据包是这样子的:

可以看到,当远程服务器192.168.66.123网络失去连接之后,本地机器(192.168.66.120)每隔一秒重发了9次tcp keep-alive probe,最终认为这个TCP连接已经失效,发了一个RST包给192.168.66.123。

为什么应用层需要heart beat/心跳包?

默认的tcp keep-alive超时时间太长

默认是7200秒,也就是2个小时。

socks proxy会让tcp keep-alive失效

socks协议只管转发TCP层具体的数据包,而不会转发TCP协议内的实现细节的包(也做不到),参考socks_proxy

所以,一个应用如果使用了socks代理,那么tcp keep-alive机制就失效了,所以应用要自己有心跳包。

socks proxy只是一个例子,真实的网络很复杂,可能会有各种原因让tcp keep-alive失效。

移动网络需要信令保活

前两年,微信信令事件很火,搜索下“微信 信令”或者“移动网络 信令”可以查到很多相关文章。

这里附上一个链接:微信的大规模使用真的会过多占用信令,影响通讯稳定吗?

总结

  • TCP keep-alive是通过在空闲时发送TCP Keep-Alive数据包,然后对方回应TCP Keep-Alive ACK来实现的。
  • 为什么需要heart beat/心跳包?因为tcp keep-alive不能满足人们的实时性的要求,就是这么简单。
时间: 2025-01-01 23:59:03

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

tcp连接探测Keepalive和心跳包

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

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

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

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

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

Delphi2010中DataSnap高级技术(5)—建立稳定服务程序之TCP心跳包的使用

为了能让我们的服务程序更加稳定,有些细节问题必须解决.就如上一讲中提到的客户端拔掉网线,造成服务器上TCP变成死连接,如果死连接数量过多,对服务器能长期稳定运行是一个巨大的威胁. 另外,经过测试,如果服务器上有TCP死连接,那么服务程序连接数据库,也会产生那个一个死连接.这样的话,给数据库服务器也造成威胁.所以,服务器程序编写的好坏,直接影响系统的稳定性! 如何解决TCP死连接的问题,有多种方法,其中最有效的就是心跳包技术. 我们在DSServer的OnConnect事件中加入心跳包代码 use

TCP之心跳包实现思路

原文 http://www.cnblogs.com/Leo_wl/p/3334040.html 说起网络应用编程,想到最多的就是聊天类的软件.当然,在这类软件中,一般都会有一个用户掉线检测功能.今天我们就通过使用自定义的HeartBeat方式来检测用户的掉线情况. 心跳包实现思路 我们采用的思路是:客户端连接上服务端以后,服务端维护一个在线用户字典,客户端每隔一段时间,向服务器发送一个心跳包,服务器接收到包以后,字典 数据的值都会更新为0:一旦服务端超过规定时间没有接收到客户端发来的包,字典数据

android tcp通信如何做到心跳管理

问题描述 android tcp通信如何做到心跳管理 我想实现一个TCP通信:点击登陆后将用户名和密码打包(包为bytes)发送给服务器后,服务器发送包给客户端.登陆成功后还需要做两个动作:1.客户端没隔30S给客户端发送一次bytes :2.当服务器有数据过来时,客户端自动接收数据.现在的问题是我是做两个线程还是做一个线程呢.我做了两个线程,一个接一个发,但是我怎么实现第二点呢.哪位大神可以给我点详细的指点么.本人新手,菜鸟一个.跪求大神指点. 解决方案 获取输入流,用read方法返回值判断是

心跳包机制

心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着.事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包. 在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE.系统默认是设置的2小时的心跳频率.但是它检查不到机器断电.网线拔出.防火墙这些断线.而且逻辑层处理断线可能也不是那么好处理.一般,如果只是用于保活还是可以的. 心跳包一般来说都是在逻辑层发送空的

c++builder-C++ Builder心跳包的问题

问题描述 C++ Builder心跳包的问题 大家好,小弟最近在研究DataSnap服务器心跳包的问题 我用的是TDSTCPServerTransport控件 客户端用TSQLConnection连接 看网上的帖子说只需要在TDSTCPServerTransport中设置心跳属性就可以了 当客户端没有网络异常时,服务器会在超时后触发心跳,结束后为触发TDSTCPServerTransport的DSTCPServerTransportDisconnect事件. 但是我在客户端断开网络之后,服务器一

心跳包

一般是用来判断对方(设备,进程或其它网元)是否正常动行,一般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉.用于检测TCP的异常断开. 一般是用来判断对方(设备,进程或其它网元)是否正常动行,一般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉.用于检测TCP的异常断开. 基本原因是服务器端不能有效的判断客户端是否在线也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况.所谓的心跳包就是客户端定时发送简单的信息给服务器端告