计算机网络:(十六)TCP 的运输连接管理

前言

当你打开浏览器访问网页、用聊天软件发消息时,背后其实有一个"隐形的管理者"在工作------它负责帮你的设备和目标服务器"打好招呼"、"按规矩传数据",最后"礼貌告别"。这个管理者,就是 TCP 的运输连接管理

TCP 和 UDP 最大的区别在于"面向连接":UDP 像寄明信片,写完直接扔邮筒,不管对方收没收到;而 TCP 像打电话,要先等对方接起(建立连接)、说清楚要聊什么(协商规则)、聊完再挂电话(释放连接)。

  • 接下来我们就一步步拆解这个"打电话"的全过程,让你搞懂 TCP 是怎么管理连接的。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343

我的计算机网络专栏,欢迎来阅读
https://blog.csdn.net/2402_83322742/category_12909527.html

一、TCP 的运输连接管理

首先要明确:TCP 运输连接的生命周期分 3 个核心阶段,所有管理工作都是为了让这 3 个阶段"平稳落地"。

1.1 运输连接的三个阶段

TCP 连接从建立到结束,就像一次打电话的过程,分为 3 步:

阶段 核心作用(通俗理解) 对应场景举例
连接建立 双方"打招呼",确认对方在线 + 约定沟通规则 你拨打电话,对方接起后说"喂,能听到吗?",你回复"能听到"
数据传送 按约定的规则双向传数据(不丢、不重、按顺序) 你和对方互相说话,清晰且不抢话
连接释放 双方"说再见",释放占用的资源(如缓存、端口) 你说"先这样,挂了啊",对方回复"好,再见",然后挂电话

运输连接管理的目标很简单:让这三步"不出错"------比如别出现"你以为对方在线,其实没接"(连接建立失败),或者"挂了电话还占着线路"(资源泄漏)的情况。

1.2 TCP 连接建立:要解决的 3 个关键问题

在"打招呼"阶段(连接建立),TCP 必须先解决 3 个问题,否则后续传数据会一团糟:

  1. 确知对方存在:你得确认服务器真的在线,而不是拨了个空号。就像打电话时,要等对方"喂"一声,才知道人在。
  2. 协商核心参数:双方要约定"怎么传数据"------比如一次最多传多少字节(最大窗口值)、要不要用更高效的传输优化(窗口扩大选项、时间戳选项)。这就像快递员和你约定"一次送 5 个包裹,放快递柜",避免后续送错或送不下。
  3. 分配资源:双方要腾出专门的"空间"(如缓存、连接表项)来存对方发来的数据。就像你要腾出家里的桌子放快递,快递员也要腾出货车的位置装你的包裹。

1.3 TCP 的连接建立:三报文握手("请求-确认-再确认")

为了解决上面 3 个问题,TCP 用了 三报文握手(Three-way Handshake)------简单说就是"发 3 条消息,完成连接"。我们用"浏览器(客户 A)访问百度服务器(服务器 B)"举例,一步步看过程:

(1) 先搞懂 3 个关键标志位

在讲握手前,先认识 TCP 报文中的 3 个"信号",后续所有操作都靠它们:

  • SYN:"请求建立连接"的信号(相当于"喂,在吗?我要连你");
  • ACK:"确认收到消息"的信号(相当于"我收到你的话了");
  • seq:"数据包的序号"(相当于给每个消息编个号,确保对方不丢、不重复接收)。

(2) 三报文握手的详细过程

TCP 双方在握手时,会切换不同的"状态"来记录进度,我们结合状态一起看:

步骤 发送方 发送的消息内容 发送方状态变化 接收方 接收方状态变化 通俗解释
1 客户 A SYN=1(请求连接),seq=x(序号x) CLOSED → SYN-SENT 服务器 B (初始 CLOSED → 先进入 LISTEN 状态,等待连接) A 主动"敲门":"百度服务器,在吗?我要访问你,先给你发个序号 x"
2 服务器 B SYN=1(同意连接),ACK=1(确认收到x),seq=y(序号y),ack=x+1(下次我要收x+1及以后的) LISTEN → SYN-RCVD 客户 A - B 回复:"我在!收到你的序号 x 了,我也给你发序号 y,你下次给我发 x+1 就行"
3 客户 A ACK=1(确认收到y),seq=x+1(按约定发x+1),ack=y+1(下次我要收y+1及以后的) SYN-SENT → ESTABLISHED 服务器 B SYN-RCVD → ESTABLISHED A 再确认:"收到你的序号 y 了,我按约定发 x+1,你下次给我发 y+1 就行"
握手结束后:进入数据传送阶段

当双方都进入 ESTABLISHED 状态,就意味着"连接已建立",可以开始双向传数据了------比如浏览器向服务器要网页数据,服务器向浏览器发 HTML 代码,这一步会严格按之前约定的"窗口大小""序号规则"来传,确保数据不丢、不重、按顺序。

为什么是"三握手",不是"两握手"?

很多人会问:为什么不能少一步?比如 A 发 SYN,B 发 SYN+ACK,然后直接连接?

  • 答案是:避免"旧连接请求"浪费资源

比如 A 之前发过一个"旧的 SYN 请求"(因为网络延迟,迟迟没到 B),后来 A 又发了一个"新的 SYN 请求",和 B 完成了连接、传完数据、释放了连接。这时候那个"旧的 SYN 请求"突然到了 B,B以为是新请求,就会发 SYN+ACK 并等着 A 回复。如果是两握手,B 会直接进入连接状态,但 A 根本没发新请求,不会回复,B 的资源(缓存、端口)就会被一直占用,造成浪费。

而三握手时,A 看到"旧的 SYN+ACK"会忽略,不发第三次 ACK,B 等不到 ACK,就会释放资源,避免浪费。

1.4 TCP 的连接释放:四报文握手("我要关-确认-我也要关-确认")

数据传完后,TCP 不能"直接挂电话",因为它是双向通信------比如 A 说完了要挂,但 B 可能还有最后一点数据要发给 A(比如服务器还有个"结束响应"要发),所以需要"四报文握手"(Four-way Wavehand),让双方都能"体面告别"。

还是用"浏览器 A 和服务器 B"举例,看释放过程:

(1) 四报文握手的详细过程

步骤 发送方 发送的消息内容 发送方状态变化 接收方 接收方状态变化 通俗解释
1 客户 A FIN=1(请求释放连接),seq=u(当前序号u) ESTABLISHED → FIN-WAIT-1 服务器 B - A 说:"我数据传完了,要关连接了,最后给你发序号 u"
2 服务器 B ACK=1(确认收到u),seq=v(当前序号v),ack=u+1(下次收u+1及以后) ESTABLISHED → CLOSE-WAIT 客户 A FIN-WAIT-1 → FIN-WAIT-2 B 回复:"收到你的关闭请求了,我先处理下剩下的数据,你等我一下"
3 服务器 B FIN=1(我也要释放连接),seq=w(处理完数据后的序号w),ack=u+1 CLOSE-WAIT → LAST-ACK 客户 A - B 说:"我数据也传完了,现在要关连接了,最后给你发序号 w"
4 客户 A ACK=1(确认收到w),seq=u+1(按约定发u+1),ack=w+1 FIN-WAIT-2 → TIME-WAIT 服务器 B LAST-ACK → CLOSED A 回复:"收到你的关闭请求了,我等一会儿再关,你先关吧"

(2) 关键:A 必须等待 2MSL 的时间(TIME-WAIT 状态的意义)

在步骤 4 后,A 不会马上进入 CLOSED 状态,而是会进入 TIME-WAIT 状态 ,并等待 2MSL(Maximum Segment Lifetime,报文段最大生存时间)------通常 MSL 是 30 秒或 1 分钟,所以 2MSL 就是 1~2 分钟。

为什么要等这 2 分钟?核心是"双保险":

  1. 确保 B 能收到最后一个 ACK:A 发的最后一个 ACK 可能丢了,B 没收到会重发 FIN。A 等 2MSL,就能收到 B 重发的 FIN,然后再重发一次 ACK,避免 B 一直等 ACK 而不释放资源。
  2. 避免旧报文干扰新连接:A 等 2MSL,能让本连接中所有"飘在网络里的旧报文"(比如延迟的数据包)都失效。这样下次 A 再和 B 建立新连接时,不会遇到这些旧报文,避免搞混数据。

当 2MSL 时间到,A 才会从 TIME-WAIT 进入 CLOSED 状态,至此整个 TCP 连接完全释放。

(3) 为什么是"四挥手",不是"三挥手"?

因为 TCP 是双向的,B 收到 A 的 FIN 后,可能还有数据要传(比如步骤 2 到步骤 3 之间的"处理剩下的数据"),不能马上发 FIN,必须先回复 ACK 表示"收到关闭请求",等数据传完再发 FIN。如果是三挥手,B 会把 ACK 和 FIN 合并成一条消息,但这样会导致 A 误以为 B 没有剩余数据,可能提前关闭,丢数据。

1.5 TCP 的有限状态机:连接的"操作手册"

前面讲了连接建立和释放时的状态变化,但 TCP 有哪些状态?什么时候会切换?用"有限状态机"(Finite State Machine)就能一目了然------它就像 TCP 的"操作手册",规定了"在什么条件下,从哪个状态切换到哪个状态"。

(1) 先认识 TCP 的 11 个核心状态

TCP 所有状态可以按"生命周期阶段"分类,避免记混:

状态分类 状态名称 状态含义(通俗解释)
初始/终止状态 CLOSED 连接未建立或已完全释放(相当于电话没拨,或已经挂了)
监听状态 LISTEN 服务器处于"等待连接"状态(相当于百度服务器一直开着,等用户访问)
连接建立相关 SYN-SENT 客户发了 SYN,等服务器的 SYN+ACK(相当于你拨了电话,等对方接)
连接建立相关 SYN-RCVD 服务器收了 SYN,发了 SYN+ACK,等客户的 ACK(相当于对方接了电话,等你说话)
数据传输状态 ESTABLISHED 连接已建立,可双向传数据(相当于你和对方正在聊天)
连接释放相关 FIN-WAIT-1 客户发了 FIN,等服务器的 ACK(相当于你说"要挂了",等对方回复)
连接释放相关 FIN-WAIT-2 客户收了服务器的 ACK,等服务器的 FIN(相当于对方说"知道了,等我说完",你等对方挂)
连接释放相关 CLOSE-WAIT 服务器收了客户的 FIN,发了 ACK,等自己传完数据(相当于你说"要挂了",对方说"知道了",但对方还有话没说)
连接释放相关 LAST-ACK 服务器发了 FIN,等客户的 ACK(相当于对方说"我也说完了,挂了",等你确认)
连接释放相关 CLOSING 客户和服务器同时发 FIN(相当于你和对方同时说"要挂了",互相等 ACK)
连接释放相关 TIME-WAIT 客户收了服务器的 FIN,发了 ACK,等 2MSL(相当于你确认对方要挂了,等一会儿再挂)

(2)状态变迁的"核心流程"(结合三握手+四挥手)

有限状态机的箭头太多,我们只记"正常流程"(忽略异常情况),和之前的三握手、四挥手对应:

连接建立的状态链(客户 A + 服务器 B)
  • 客户 A(主动打开):CLOSED → 发 SYN → SYN-SENT → 收 SYN+ACK → 发 ACK → ESTABLISHED
  • 服务器 B(被动打开):CLOSED → 开启监听 → LISTEN → 收 SYN → 发 SYN+ACK → SYN-RCVD → 收 ACK → ESTABLISHED
数据传输:稳定在 ESTABLISHED 状态

双方在这个状态下双向传数据,直到一方想释放连接。

连接释放的状态链(客户 A 先发起释放)
  • 客户 A(主动关闭):ESTABLISHED → 发 FIN → FIN-WAIT-1 → 收 ACK → FIN-WAIT-2 → 收 FIN → 发 ACK → TIME-WAIT → 等 2MSL → CLOSED
  • 服务器 B(被动关闭):ESTABLISHED → 收 FIN → 发 ACK → CLOSE-WAIT → 传完数据发 FIN → LAST-ACK → 收 ACK → CLOSED
特殊情况:同时关闭(CLOSING 状态)

如果客户 A 和服务器 B 同时发 FIN,那么 A 会从 FIN-WAIT-1 进入 CLOSING 状态(而不是 FIN-WAIT-2),B 也会从 ESTABLISHED 进入 CLOSING 状态;等双方都收到对方的 ACK 后,再进入 TIME-WAIT 状态,最后到 CLOSED

(3)常见异常状态变迁(了解即可)

  • SYN-SENTCLOSED:客户发了 SYN 后,等了很久没收到回复(超时),主动关闭。
  • LISTENCLOSED:服务器关闭监听(比如百度服务器维护,暂时不接受新连接)。
  • SYN-RCVDCLOSED:服务器收了 SYN 后,等了很久没收到客户的 ACK(超时),释放资源。

以上就是本篇博客的全部内容,下一篇我们继续探讨计算机网络里面的知识。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343

我的计算机网络专栏,欢迎来阅读
https://blog.csdn.net/2402_83322742/category_12909527.html

|------------------------------------|
| 如果您觉得内容对您有帮助,欢迎点赞收藏,您的支持是我创作的最大动力! |