TCP之Keep-Alive介绍

1. TCP Keep-Alive 选项

很多刚接触 TCP 编程的人会惊讶地发现,在没有数据读写的“静默”的连接上,是没有办法发现 TCP 连接是有效还是无效的。比如客户端突然崩溃,服务器端可能在几天内都维护着一个无用的 TCP 连接。前面提到的例子就是这样的一个场景。

那么有没有办法开启类似的“轮询”机制,让 TCP 告诉我们,连接是不是“活着”的呢?

这就是 TCP 保持活跃机制所要解决的问题。实际上,TCP 有一个保持活跃的机制叫做 Keep-Alive。

这个机制的原理是这样的:

定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

上述的可定义变量,分别被称为保活时间、保活时间间隔和保活探测次数。在 Linux 系统中,这些变量分别对应 sysctl 变量net.ipv4.tcp_keepalive_time、net.ipv4.tcp_keepalive_intvl、 net.ipv4.tcp_keepalve_probes,默认设置是 7200 秒(2 小时)、75 秒和 9 次探测。

这些属性可以在/proc/sys/net/ipv4/下查看:

cat /proc/sys/net/ipv4/tcp_keepalive_time 7200 cat /proc/sys/net/ipv4/tcp_keepalive_probes 9 cat /proc/sys/net/ipv4/tcp_keepalive_intvl 75

也可以通过命令行查看:

sudo sysctl -a | grep keepalive net.ipv4.tcp_keepalive_time = 7200 net.ipv4.tcp_keepalive_probes = 9 net.ipv4.tcp_keepalive_intvl = 75

1.2 连接探活的过程

如果开启了 TCP 保活,需要考虑以下几种情况:

第一种,对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。

第二种,对端程序崩溃并重启。当 TCP 保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 连接已经被重置。

第三种,是对端程序崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

TCP 保活机制默认是关闭的,当我们选择打开时,可以分别在连接的两个方向上开启,也可以单独在一个方向上开启。如果开启服务器端到客户端的检测,就可以在客户端非正常断连的情况下清除在服务器端保留的“脏数据”;而开启客户端到服务器端的检测,就可以在服务器无响应的情况下,重新发起连接。

为什么 TCP 不提供一个频率很好的保活机制呢?我的理解是早期的网络带宽非常有限,如果提供一个频率很高的保活机制,对有限的带宽是一个比较严重的浪费。

我们可以设置SO_KEEPALIVE属性使得我们在2小时以后发现对方的TCP连接是否依然存在。

int keepAlive = 1; setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));

2.设置TCP KEEPALIVE

我们可以使用TCP的TCP_KEEPCNT、TCP_KEEPIDLE、TCP_KEEPINTVL3个选项。 这些选项是连接级别的,每个socket都可以设置这些属性。

这些选项的定义,可以通过man查看。

man 7 tcp

socket option:

TCP_KEEPCNT (since Linux 2.4) The maximum number of keepalive probes TCP should send before dropping the connection. This option should not be used in code intended to be portable. 关闭一个非活跃连接之前的最大重试次数。 该选项不具备可移植性。 TCP_KEEPIDLE (since Linux 2.4) The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes, if the socket option SO_KEEPALIVE has been set on this socket. This option should not be used in code intended to be portable. 设置连接上如果没有数据发送的话,多久后发送keepalive探测分组,单位是秒 该选项不具备可移植性。 TCP_KEEPINTVL (since Linux 2.4) The time (in seconds) between individual keepalive probes. This option should not be used in code intended to be portable. 前后两次探测之间的时间间隔,单位是秒 该选项不具备可移植性。

代码层面的设置步骤:

int keepAlive = 1; // 非0值,开启keepalive属性 int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行此TCP层的探测 int keepInterval = 5; // 探测发包间隔为5秒 int keepCount = 3; // 尝试探测的最多次数 // 开启探活 setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive)); setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle)); setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval)); setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount)

3.为什么TCP的keep avlive很牛逼了,还需要应用层心跳包?

举个栗子: 当你在网吧打游戏的时候,有人一直在挂机,这个时候从技术角度来分析,套接字是正常建立的,服务器认为此人一直再正常游戏,此时就需要应用层的心跳包来进行判定了。

免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:TCP之Keep-Alive介绍 https://www.yhzz.com.cn/a/14071.html

上一篇 2023-05-12
下一篇 2023-05-12

相关推荐

联系云恒

在线留言: 我要留言
客服热线:400-600-0310
工作时间:周一至周六,08:30-17:30,节假日休息。