TCP 核心问题 之 Keep-Alive

TCP 核心问题 之 Keep-Alive

在使用 wireshark 抓包观察 TCP 连接的时候,我发现在我与服务器建立 TCP 连接,并完成 HTTP 请求获取到数据后,服务器与我并不会马上进行 四次挥手 断开连接,而是会进行一段时间的 Keep-Alive。

这就很有意思了,Keep-Alive 这段时间是如何控制的呢?其机制是怎样的?这就是本篇想聊清楚的问题。

嗯…… 为了鲜明标识,决定 【本文将带你学会】改名为 【搁浅一下】 意思不变

搁浅一下(你将获得)

在这里插入图片描述

  1. TCP 的 Keep-Alive 机制是怎样的?
  2. TCP 如何标识 Keep-Alive 报文?
  3. 如何控制 Keep-Alive 报文间隔与断连时长?
  4. HTTP Keep-Alive ?
引子 · 根据 wireshark 抓包的推测

下图是我一次接口请求的 wireshark 抓包,我们看图说话

在这里插入图片描述

在这里插入图片描述

开始的是 三次握手 忘记的同学可以看我之前的文章,这里重点看 Keep-Alive

好,此时我们什么都不知道,但是可以根据抓包先观察分析猜测一下。

分析上图流程

  • 首先:172.16.27.247 (这是我的本机客户端 ip)率先向服务端 192.168.26.144 发起了 Keep-Alive 报文
  • 服务端会进行 Keep-Alive ACK
  • 规律是 客户端一直在发送 Keep-Alive ,服务端呢,一直在 Keep-Alive ACK,且 Seq 和 Ack 一直没有变
  • 大概过了 86 - 26 = 50 s 服务端率先发起 FIN ACK 进入 四次挥手 断连阶段

推测

  • TCP 在没有数据流通时有自己的保活机制,由客户端上报 Keep-Alive 报文,服务端 ACK ,双方确认彼此活着。
  • 有保活时间上限,在限定时间内,如果没有数据交换,即使保活心跳正常,也会进行挥手断连,释放资源。

ok 这是我的一个分析推测,那么实际是如何呢?

问 1 · TCP 的 Keep-Alive 机制是怎样的?

首先明确一点,TCP Keep-Alive 并不是 TCP 标准的一部分,而是由协议栈实现者进行拓展实现,而我们主流的系统 Linux、Windows、MacOS、BSD 都进行了对应的实现。

在 RFC1122 (Request For Comments) 给出了标准,以及为何 TCP 标准并不包含 keep-alive 机制的原因 RFC1122 Page-101

标准定义了以下几点:

  1. 对于每个 TCP 连接应用必须能够开启或者关闭 keep-alive 机制,并且 keep-alive 默认是关闭的。
  2. keep-alive 包的发送,必须在一定间隔内 没有数据交互 或者 ACK 数据包都已接收到后进行。并且 间隔 必须可配置,且默认不能少于 2 小时。
  3. 由于不带有数据的 ACK 包是不保证可靠传输的,所以 keep-alive 机制不能通过一次检测没有收到回应就判断连接已断开。
  4. keep-alive 包不应该包含任何数据,然而它可以配置包含 8 字节垃圾数据的包,以便于兼容一些不正确的 TCP 实现。

在 DISSCUSSION 中 RFC1122 给出了这样的建议

为了确认空闲连接仍然活着,这些实现会发送探测段,旨在引发对等 TCP 响应,这样的探测端通常会包含 SEG.SEQ = SND.NXT - 1 并可能包含 8 字节无效数据。即 keep-alive 包 seq 值等于前一个报文的 seq - 1

在这里插入图片描述

如我图中所示,第一个 keep-alive 报文的 seq = 293 是上一个 (seq = 294) -1。

因此这个探测包会导致接收者回复一个 Ack 报文段,以此来确认此连接仍然存活,如果对方因为网络分区或者崩溃而断开连接,它将以 RST 响应,而不是 ACK。

问 2 · TCP 如何标识 Keep-Alive 报文?

SEG.SEQ = SND.NXT - 1 即 keep-alive 包 seq 值等于前一个报文的 seq - 1 从而引发对端的 ACK 报文。

问 3 · 如何控制 Keep-Alive 报文间隔与断连时长?

控制 TCP Keep-Alive 的核心参数大概有三个,你可以通过以下命令查看

Linux 系统

cat /proc/sys/net/ipv4/tcp_keepalive_time
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
cat /proc/sys/net/ipv4/tcp_keepalive_probes

上面三行命令你应该可以在 Linux 系统下查到对应的配置

net.ipv4.tcp_keepalive_time=7200 // 发送的最后一个数据包(简单的 ACK 不被视为数据)和第一个 keepalive 探测包之间的间隔,单位 秒,如默认是 7200 秒,则为 7200 秒后发送第一个 keeplive 探测包
net.ipv4.tcp_keepalive_intvl=75 // 后续发送 keepalive 探测包的时间间隔,无论连接在此期间交换了什么,比如默认是 75s 的间隔发送下一个探测
net.ipv4.tcp_keepalive_probes=9 // 在确认连接死亡前,要发送的未被确认即没有被 keepalive-ack 的探测包数量

关于配置,大家可以参考这篇文章 usingkeepalive

Mac OS 系统

查看命令

sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000 // 同 linux tcp_keepalive_time 单位 毫秒
net.inet.tcp.keepintvl: 75000 // 同 linux tcp_keepalive_intvl 单位 毫秒
net.inet.tcp.keepcnt: 8 // 同 linux tcp_keepalive_probes

那这里就有些奇怪,我的系统是 Mac OS ,配置如上图,然而我的 keepalive 探测包在大概 1s 后就开始发送了,与系统配置不符

在这里插入图片描述

这里又牵扯出另一个概念 HTTP keep-alive

问 4 · HTTP Keep-Alive

我的 HTTP 协议版本是 1.1 ,他默认是开启 keep-alive 的,这里我通过设置他的 Header Connection 为 Close 关闭 keep-alive

在这里插入图片描述

在这里插入图片描述

wireshark 抓包如上,我进行了两次请求,此时没有了 keep-alive 包,而是在每次请求数据交换完毕后就直接进行了挥手断连。

而我如果开启 Connection = keep-alive 进行两次请求呢?

在这里插入图片描述

在这里插入图片描述

这里很明显的进行了 keep-alive ,并且两次请求复用了一个 TCP 连接,整个过程仅有一次 握手建立连接 和 挥手断开连接。

所以普遍的,我们内核系统的 TCP Keep-Alive 是默认关闭的,你也可以通过程序代码配置当前 TCP Socke 开启保活机制,而 HTTP 的 Keep-Alive 可以影响 TCP 层面的 Keep-Alive 也就是我们是否复用一个 TCP 连接进行 HTTP 请求

吐槽时刻:

不行了,我得吐槽下,这部分可略过哈。

我原以为,这篇文章应该比较短,然而越看牵扯东西越多,想讲清楚不容易啊,而且最后由解释 Keep-Alive 机制 变成了:

到底是谁控制了我的 TCP Keep-Alive 间隔,至少到目前,系统层面的配置是没生效的,毕竟 2 小时开始发,结果我这 1 s 后就开始发了。

临时起意,加一部分,TCP Keep-Alive 、HTTP Keep-Alive、Nginx Keep-Alive、Tomcat Keep-Alive、Undertow Keep-Alive、客户端、服务端,到底是谁的配置在生效?!!(说实话,这块都能独立写一篇了,要不要拆分呢?)

时隔一周 摸了一周,换换脑子

以上,我怀疑是我请求的测试服务器配置的问题,这里我尝试请求 CSDN 北京服务器的 ip 182.92.187.217

在这里插入图片描述

结果是喜人的,干干净净的抓包

在这里插入图片描述

看的出来,从握手,到 HTTP ,到确认收到后,我们直接进行了挥手断连,我请求的 keep-alive 参数完全没有起作用(这说明服务器并没有做相关配置)啊……干净的让人舒服,教课级别的请求断连流程,让我们为 CSDN 鼓掌,啊。

这时候可能就有人要问了:”啊(尖声)!那你,前面的 keep-alive 包是怎么回事?是谁配置的?谁的配置在生效?“

好!好问题,谁问的? 这位同学请出门右转好吧 (@**@¥#%¥&*&)

留个悬念,我们下期再见!(一定不是不想写了才这样结束的)

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dying 搁浅

两杯酒,一杯敬你余生多欢喜。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值