Lazy loaded image
TCP链接和释放
Words 2591Read Time≈ 7 min
2026-7-23
2026-10-10
PASSWORD
SHOW
SHOW
TYPE
Post
STATUS
Published
SLUG
/tcp
SUMMARY
TAGS
学习
记录
ICON
CODEURL
DATE
Jul 23, 2026
PAGE
MODULE
计算机网络
😀
TCP三次握手和四次挥手简单理解记录

TCP 连接


一、 基础概念与核心机制

基础认知:

  • 全双工 (Full-Duplex):TCP 连接允许双方在任何时候独立发送和接收数据。这意味着连接的建立是双向的,连接的释放也必须是双向的。
  • 序列号 (Sequence Number):TCP 是面向字节流的协议。每个字节都有编号(初始序列号 ISN + 偏移量)。序列号用于保证数据按序到达、去重以及实现可靠传输。
  • 标志位 (Flags):
    • SYN (Synchronize):同步序列号,用于建立连接。
    • ACK (Acknowledgment):确认收到数据。
    • FIN (Finish):发送方数据发送完毕,请求释放连接。
    • RST (Reset):强制重置连接,通常表示异常。
  • 初始序列号 (ISN) 的生成机制:
    • 误区:ISN 并非固定为 0,也不是纯随机数。
    • 原理:现代操作系统通常基于时钟(如每 4 微秒加 1)生成 ISN。
    • 核心原因:防止历史报文被错误接收(如果每次从 0 开始,旧连接的延迟报文可能被新连接误认为有效);同时增加安全性,防止黑客猜测序列号进行 TCP 劫持。

二、 TCP 连接建立:三次握手 (Three-Way Handshake)

核心目的:同步双方的初始序列号 (ISN),确认双方的收发能力都正常。

1. 场景模拟 (Alice 打电话给 Bob)

  • Alice: “Bob 你可以听到我说话吗?我是 Alice。” (SYN)
  • Bob: “可以听到。Alice 你听得到我说话吗?我是 Bob。” (SYN + ACK)
  • Alice: “可以听到,那我们开始聊正事。” (ACK)

2. 详细流程与状态变迁

假设 Client(简写为 C)的初始序列号为 x,Server(简写为 S) 的初始序列号为 y。
步骤
方向
标志位 / 内容
状态变迁
说明
1
C -> S
SYN=1, Seq=x
C: SYN-SENT
客户端请求建立连接。标准 SYN 报文不能携带数据,但消耗一个序号。
2
S -> C
SYN=1, ACK=1, Seq=y, ack=x+1
S: SYN-RCVD
服务器确认收到 SYN (ack=x+1),同时发起自己的连接请求 (Seq=y)。
3
C -> S
ACK=1, Seq=x+1, ack=y+1
C: ESTABLISHED S: ESTABLISHED
客户端确认收到服务器的 SYN。ACK 报文如果没数据,不消耗序号。

3. 常见问题

  • Q1: 为什么要三次握手,两次不行吗?
    • 防坑答案:主要不是为了确认“双方都能收发”,而是为了防止失效的连接请求突然传到了服务端。
    • 场景:Alice 发出的第一个 SYN 堵在网络里了,Alice 以为丢了重发了一个。连接建立并结束后,那个堵住的旧 SYN 才到达 Bob。
    • 如果是两次握手:Bob 收到旧 SYN 立刻建立连接并分配资源,等于白白浪费资源等待 Alice 发数据。
    • 如果是三次握手:Bob 回复 SYN+ACK,Alice 收到后发现“我没想连啊”,发 RST 拒绝,Bob 释放资源。
  • Q2: 第三次握手失败了怎么办?
    • 服务端发了 SYN+ACK 后如果没有收到客户端的 ACK,会重传 SYN+ACK (指数退避)。如果多次重传仍无反应,服务端会强制关闭连接。
  • Q3: SYN Flood 攻击与防御?
    • 攻击原理:攻击者伪造大量虚假 IP 发送 SYN。服务器回复 SYN+ACK 后死等第三次 ACK,导致半连接队列 (SYN Queue) 被占满,耗尽服务器资源。
    • 防御手段:开启 SYN Cookies。服务器收到 SYN 后不立即分配资源,而是根据源 IP、端口等计算出一个 Cookie 作为序列号发回去。只有收到合法 ACK 才分配资源。
  • Q4: SYN 报文绝对不能带数据吗? (TCP Fast Open)
    • 在标准 TCP 中,SYN 不能携带应用层数据。
    • 但在 TFO (TCP Fast Open) 扩展中,客户端可以在 SYN 报文中携带数据(通过首次连接颁发的 Cookie 机制),从而减少一次 RTT(往返时间),常用于 HTTP 请求优化。

三、 TCP 连接释放:四次挥手 (Four-Way Wave)

核心目的:TCP 是全双工的,关闭必须是双向的。我不发了,但我还可以收。

1. 场景模拟 (Alice 和 Bob 挂电话)

  • Alice: “我的事说完了,我不说了,你继续说。” (FIN) —— Alice 进入半关闭状态
  • Bob: “好的,我知道你的事说完了,那我接着说。” (ACK) —— Bob 还能继续说 (此时可能有数据在传输,Bob 继续告诉 Alice 一些事情)
  • Bob: “我也说完了,挂了吧。” (FIN)
  • Alice: “好,再见。” (ACK) (进入 TIME-WAIT,等待 2MSL 后关闭)

2. 详细流程与状态变迁

假设 Client(简写为 C) 结束时的序列号为 u,Server(简写为 S) 结束时的序列号为 v。
步骤
方向
标志位 / 内容
状态变迁
说明
1
C -> S
FIN=1, Seq=u
C: FIN-WAIT-1
客户端请求关闭发送通道。FIN 报文即使没数据也消耗一个序号。
2
S -> C
ACK=1, Seq=v, ack=u+1
S: CLOSE-WAIT C: FIN-WAIT-2
服务器确认。此时处于半关闭状态:C 不能发数据,但 S 还能发,C 照样收。
(数据)
S -> C
...
...
(Server 将剩余数据发送完毕)
3
S -> C
FIN=1, ACK=1, Seq=w, ack=u+1
S: LAST-ACK
服务器数据发完了,请求关闭它的发送通道。
4
C -> S
ACK=1, Seq=u+1, ack=w+1
C: TIME-WAIT S: CLOSED
客户端确认。注意:Client 进入 TIME-WAIT,并没有直接关闭!

3. 常见问题

  • Q1: 为什么建立是三次,释放却要四次?
    • 核心原因:建立连接时,Server 的应答 (ACK) 和同步请求 (SYN) 可以合并在同一个包 (SYN+ACK) 里发送。
    • 但在释放时,Client 发 FIN 只是说“我发完了”。Server 收到后先回 ACK(防超时重传),但 Server 可能还有数据没传完,不能立刻发 FIN。所以 ACK 和 FIN 分家了。
  • Q2: TIME-WAIT 状态为什么要等 2MSL?
    • 定义:主动发起关闭的一方,发送完最后一个 ACK 后,必须等待 2MSL (Maximum Segment Lifetime,最长报文段寿命,Linux 通常默认 60 秒) 才能进入 CLOSED 状态。
    • 原因 1 (保底):防止最后一个 ACK 丢了。如果 Server 没收到 ACK,会重传 FIN。Client 如果早早跑了,Server 就永远收不到回复了。Client 必须等着扫尾。
    • 原因 2 (清场):防止“已失效的连接请求报文段”出现在下一个新连接中。等待 2MSL 可以让本连接产生的所有报文都在网络中消逝(1 MSL 去,1 MSL 回)。
    • 为什么是 2MSL 而不是 1MSL?:刚好覆盖了“ACK 丢失导致对端重传 FIN”的一个完整来回时间。如果只有 1MSL,ACK 丢了,对端重传 FIN 时,客户端已关闭,会回复 RST,导致服务端异常。
  • Q3: CLOSE-WAIT 状态过多说明什么?
    • 说明服务器端的代码可能有 Bug。收到了客户端的 FIN,回复了 ACK,但迟迟没有发起自己的 FIN(比如忘记在代码中调用 close() 函数),导致连接一直卡在半关闭状态,占用文件描述符和内存。

四、 异常场景与边界情况

  1. 同时打开 (Simultaneous Open)
      • 双方几乎同时发送 SYN。状态变为:SYN-SENT -> SYN-RCVD -> ESTABLISHED。
      • 依然需要交换四次报文(因为无法合并),但逻辑上依然称为“三次握手”的变体。
  1. 同时关闭 (Simultaneous Close)
      • 双方几乎同时发送 FIN。状态变为:FIN-WAIT-1 -> CLOSING -> TIME-WAIT。
      • 双方都需要等待 2MSL 才能关闭。
  1. RST (Reset) 报文的作用
      • 当收到不期望的报文(如未监听的端口收到 SYN,或已关闭的连接收到数据)时,会发送 RST 强制断开连接,不经过四次挥手。
      • 这也是排查 Connection reset by peer 错误的根源。
  1. TCP 保活机制 (Keepalive)
      • 在 CLOSE-WAIT 过多的问题中,提到了占用资源。
      • 补充 TCP Keepalive 机制(心跳包)。服务器可以通过 SO_KEEPALIVE 选项,定期探测死连接,从而清理掉那些因为客户端崩溃而卡在 CLOSE-WAIT 的连接。

五、 对比总结

1. 极简对比总结表

特性
三次握手 (建立)
四次挥手 (释放)
发起方
通常称 Client
双方都可以发起,通常是 Client
关键标志
SYN -> SYN+ACK -> ACK
FIN -> ACK -> (数据) -> FIN -> ACK
消耗序号?
SYN 消耗 1
FIN 消耗 1
中间状态
SYN-SENT, SYN-RCVD
FIN-WAIT, CLOSE-WAIT, TIME-WAIT
等待
无
TIME-WAIT (2MSL)
核心逻辑
1. 我想连 2. 确认你想连,我也想连 3. 好的,确认
1. 我不发了 2. 知道了 (还能发) 3. 我也不发了 4. 拜拜

2. 常见考法

  1. ACK 确认号怎么算?
      • 永远是“对方发来的序号 + 数据长度”。
      • 如果对方发的是 SYN 或 FIN (占 1 个序号),就是 对方 Seq + 1。
  1. 谁进入 TIME-WAIT?
      • 主动发起关闭的一方。如果服务器主动踢人,服务器会进入 TIME-WAIT。
  1. 记忆口诀
      • 三次握手:SYN, SYN+ACK, ACK (请求,确认+请求,确认)
      • 四次挥手:FIN, ACK, FIN, ACK (分手,知道,我也分,拜拜)
      • TIME-WAIT 等待 2MSL:等最后 ACK 不丢,等旧包全部死绝
💡
有关Notion安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
 
上一篇
明信片-古风系列3
下一篇
建站方法

Comments
Loading...