TCP之Keep-Alive介绍

gcp 2020-11-09 19:56:03 2824

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很牛逼了,还需要应用层心跳包?

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

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
gcp
红包 15 1 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
gcp
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区