为什么基于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不能满足人们的实时性的要求,就是这么简单。
时间: 2024-08-08 02:05:31

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

TCP心跳包与KeepAlive

"cli和ser建立连接后,cli挂掉,ser知道吗?" 方法1:应用层自己实现的心跳包TCP socket心跳机制中,心跳包可以由服务器发送给客户端,也可以由客户端发送给服务器,不过比较起来,前者开销可能更大.因此一般是由客户端给服务器发送心跳包.比如这个示例:https://blog.csdn.net/lisonglisonglisong/article/details/51327695 方法2:TCP的KeepAlive保活机制 --"断电和超时是同一个现象..只能按超

心跳包(HeartBeat)

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

Twisted 库 TCP 服务器 心跳包demo

最近刚刚接触 twisted 库,感觉twisted 库的设计模式和平时接触的socket 通信很大不同, 感觉有点不大适应,为了增加自己对twisted 的适应度, 同时也熟悉一下心跳包的机制. 特地写了一个  基于twisted 库的 TCP  服务器 心跳包 demo. 以供练习之用. 同时也和大家分享 python 编程心得  demo 特性描述: 1   TCP服务器支持多客户端连接, 每次客户端连接之后,直接将客户端信息(IP 地址, 端口号)存储到字典当中. 并且启动Svr_uni

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

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

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

很多应用层协议都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据.使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议. 学过TCP/IP的同学应该都知道,传输层的两个主要协议是UDP和TCP,其中UDP是无连接的.面向packet的,而TCP协议是有连接.面向流的协议. 所以非常容易理解,使用UDP协议的客户端(例如早期的“OICQ”,听说OICQ.com这两天被抢注了来着,好古老的回忆)需要定时向服务器发送心跳包

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

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

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

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

TCP心跳包

所谓的心跳包就是客户端定时放送简单的信息给服务器端,告诉它我还在而已.代码就是每 隔几分钟发送一个固定信息给服务器端,服务器端回复一个固定信息.如果服务器端几分钟后没有收到客户端信息则视客户端断开.比如有些通信软件长时间不适 用,要想知道它的状态是在线还是离线,就需要心跳包,定时发包收包. 心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活在.事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,活着只包含包头的一个空包

【转载】TCP socket心跳包示例程序

在做游戏开发时,经常需要在应用层实现自己的心跳机制,即定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性. 在TCP socket心跳机制中,心跳包可以由服务器发送给客户端,也可以由客户端发送给服务器,不过比较起来,前者开销可能更大.-- 这里实现的是由客户端给服务器发送心跳包,基本思路是: 1) 服务器为每个客户端保存了IP和计数器count,即map<fd, pair<ip, count>>.服务端主线程采用 select 实现多路IO复用,监听新连