TCP 核心问题剖析之 “四次挥手”

TCP 核心问题剖析之 断连我只想 “三次挥手” 你凭什么让我 “挥手四次” ?

想必看过我的 三握 文章的同学应该对 ”握手“ 和 ”挥手“ 这个概念有所理解了,其实就是数据交互。就是我给你发条消息,你接受处理,回你条消息,你接受处理如此而已。

那怎么到了断开连接的时候,就要 ”挥手四次“ 了呢

  1. A 说:我要断开连接
  2. B 说:收到断吧
  3. A 说:收到我断了

这样是不也就 ok 了呢?感觉好像没问题?本文从将从这里开始

照例

本文将带你学会
  1. 什么是 TCP 四次挥手
  2. 断开连接,我只想挥手三次,你凭什么让我挥手四次?
  3. 二次挥手 ACK 对方跑路了咋办?
  4. CLOSE_WAIT 在等啥?
  5. TIME_WATI 2MSL 等待两个最大报文存活时长意欲何为?
TCP ”四次挥手“ 断连

聊为什么之前,先看看是什么?

在这里插入图片描述

172.16.26.177 是 Client 客户端地址,192.168.26.144 是 Server 服务提供方地址。

可以看到,经过一段时间 keep-alive 之后,服务端觉得,闹够了!我要断连!流程如下

一次挥手 :172.16.26.177 --> 192.168.26.144 我要断连! 发送标志位 FIN ACK ,这里 Ack 的值是上次来包的 seq + 1 (即 6572 C 发给 S 的 seq )

图中 Seq = 430 Ack = 295

看网上大部分都只说了 FIN 标志位,那其实 ACK 标志位也是 1 ,所以准确说应该是 FIN ACK

二次挥手:192.168.26.144 --> 172.16.26.177 我收到了你的断链请求。ACK 这次挥手是确认第一次挥手的 FIN ACK 收到了 (注意此时不是告知你可以断开连接了)

此时 Seq = 295 Ack = 431

复习一下,Seq 为本段报文数据第一个字节编号, Ack 为期望下次收到下个报文 Seq 值 = 要确认报文 Seq 值 + 要确认报文数据字节数

三次挥手:192.168.26.144 --> 172.16.26.177 好我这没问题,可以断连。FIN ACK 第三次挥手是被断连方发送确认可断连报文,此时的 Seq 和 Ack 和 二次挥手一样

四次挥手:172.16.26.177 --> 192.168.26.144 好的收到。ACK 告诉被断连方,我收到了你的断连确认。

此时 Seq = 431 Ack = 296

通常来说都会给一个状态流程图来方便理解,这里我也画了一个来辅助认识

在这里插入图片描述

为啥是 四次 不是 三次

我们看看 “三次挥手” 行不行,也就是说 四挥手确认 不要了。

在这里插入图片描述

似乎不太行,这样我无法确认 三挥手 FIN ACK 已经被收到,如果三次挥手的 FIN ACK 包在网络中丢失,那我可能会长时间处于 FIN_WAIT2 状态。

仔细观察,其实所谓的 “四次挥手” 我们主要的是两次的 FIN ACK 断连报文,而剩下的两次是对这两次的 FIN ACK 的确认。

看着减少不行,那我能不能多挥几次?当然可以,但没有必要,对于这种通信,我们追求的是在最少的通信次数内做好,即只做必要的事。

好,那我不删 第四次,我删 第二次 好吧?让你断你就断,分什么 ACK + FIN ACK

好,这里没了 CLOSE_WATI 状态,那我们就要解释下这个状态的用处

CLOSE_WAIT 在等啥?

我们发起断连请求时,对方可能存在有些数据包没发完,或者有些包没收到确认,那么等所有包都确认送达后,我才会告诉你可以断开了。故而这里的 ACK 也不能去。

这是可能有人(TMD 是谁?!)就说了:诶?不对!我这也行啊,我等确认收完再直接发 FIN ACK 不就行了?

行,你可真行,真是个小机灵鬼。

这里我认为是这样的:首先 TCP 要求每个报文都要有 ACK 确认,这个是设计原则不可变,那么没有收到 ACK 就会重试发包直到确认收到。

可以理解为这是个通用的机制,而上面的这个操作,你等全部确认发完,可能会有一段时间,这个会影响到通用机制不停的重发,所以为了保证我们的机制,要接收到报文后立刻确认我收到,故而有了,FIN_WAIT1 和 FIN_WAIT2 两个状态。

你说他们有本质区别吗?我觉得没有,这是一个机制设计的问题,取舍后保留较为合理的,更加可读易懂的。

TIME_WATI 2MSL 等待两个最大报文存活时长意欲何为?

细心的同学应该发现,我们 断连发起方,在四次挥手 ACK 后,仍然等待了两个 MSL (最大报文存活时长)才进入了 CLOSED 状态。

协议规定 MSL 为 2 分钟,实际应用中常用的是 30 秒,1 分钟和 2 分钟等

这是因为,我们要确认 被断连方 收到了我们的 ACK ,为了防止无限的 ACK 下去,我们这里兜底等待 2MSL 时长,如果被断连方没收到 ACK 它会重新发送 FIN ACK 可断报文,此时我们可以补发 ACK。

如果超过了这个时长,我就不管了,已经仁至义尽,之后来的我们直接返回 RST 重置报文,让他重置连接吧。

二次挥手 ACK 对方跑路了咋办

可能你又有疑问了,我们的网络环境纷繁复杂,啊……我可不确认明天和意外谁先来临,难道我 FIN ACK 了对方,对方就一定能回复我么?

我看未必,服务宕机,浏览器关闭,电脑挂机,机房着火,如果意外可能存在,那么它必定存在。

咋办,那我就一直 FIN_WAIT 吗?如何处理?

自然而然,想到了超时,我设置个超时,如果长时间没有收到 ACK ,我也不管你了,我就直接自己断了,你爱咋咋吧。

确实可以,然而 TCP 没有为我们提供这种机制,好在 Linux 为我们提供了 tcp_fin_timeout 这个参数,设置超时时间来处理这种情况。

感谢 Linux ,否则我可要等死了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dying 搁浅

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

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

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

打赏作者

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

抵扣说明:

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

余额充值