飞翔飞翔
主页
  • 计算机基础

    • TCP协议
  • 数据库

    • SQL教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP协议
  • 数据库

    • SQL教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • TCP协议

    • TCP 简介与分层模型
    • TCP 连接管理
    • TCP 可靠传输机制
    • TCP 粘包与拆包
    • TCP 拥塞控制
    • TCP 头部字段详解
    • TCP 与 UDP 对比
    • TCP Socket 编程实践
    • TCP 抓包实战
    • TCP 安全与面试综合题

TCP 连接管理

三次握手、四次挥手、TCP 状态机与 TIME_WAIT — 这是面试最高频的 TCP 考点。


1. 为什么需要三次握手?

TCP 是面向连接的协议。通信前,双方需要确认彼此的收发能力正常,同时交换初始序列号(ISN)。

核心问题:网络中存在延迟的旧 SYN 段,如果没有三次握手,可能错误地建立"幽灵连接"。三次握手确保双方都确认了对方的序列号,且连接请求是"新鲜的"。

RFC 9293 明确指出:三次握手是必要的,因为序列号不绑定到网络的全局时钟,接收方无法知道收到的 SYN 是不是旧的,必须让发送方验证。


2. 三次握手(Three-Way Handshake, 3WHS)

以客户端(主动打开)连接服务器(被动打开)为例:

      客户端                          服务器
        |                               |
    CLOSED                           LISTEN
        |                               |
    ①  |── SYN, seq=x ───────────────→  |  SYN-RECEIVED
        |                               |
    ②  |←─ SYN+ACK, seq=y, ack=x+1 ───|  SYN-RECEIVED
        |                               |
    ESTABLISHED                         |
    ③  |── ACK, seq=x+1, ack=y+1 ────→ |  ESTABLISHED
        |                               |

各步详解

步骤方向内容客户端状态服务器状态
①C→SSYN=1, seq=x(客户端 ISN)SYN-SENTSYN-RECEIVED
②S→CSYN=1, ACK=1, seq=y, ack=x+1ESTABLISHEDSYN-RECEIVED
③C→SACK=1, seq=x+1, ack=y+1ESTABLISHEDESTABLISHED

关键点:

  • 步骤 ② 中将 SYN 和 ACK 合并为一条消息("捎带"),这是能省掉一次往返的关键
  • 步骤 ③ 的 ACK 不消耗序列号(纯 ACK 段 seq 不变)
  • 连接建立后,后续数据段 seq 从各自 ISN+1 开始

为什么不是两次握手?

如果只有两次握手:客户端发 SYN → 服务器回 SYN+ACK 就认为连接建立。但若客户端第一个 SYN 在网络中延迟,客户端超时后重新发了 SYN 并完成通信。之后旧 SYN 到达服务器,服务器回 SYN+ACK 就建立了无效连接,浪费资源。


3. TCP 状态机

RFC 9293 定义了 11 个 TCP 状态:

                              +---------+
                              |  CLOSED |
                              +---------+
                                |     ^
                   passive OPEN |     | CLOSE
                                V     |
                              +---------+
                              |  LISTEN |
                              +---------+
                                |     |
                          rcv SYN    |  snd SYN
                                |     V
+---------+                  +---------+
|  SYN    |<-- rcv SYN ------|  SYN    |-- snd SYN,ACK --> +---------+
|  RCVD   |                  |  SENT   |                   |  SYN    |
+---------+-- snd SYN,ACK -->+---------+<-- rcv SYN,ACK --|  RCVD   |
      |                           |                        +---------+
      | rcv ACK of SYN            | rcv ACK of SYN              |
      V                           V                             |
+-------------------  ESTABLISHED  -----------------------------+
      |                               |
   CLOSE|                          rcv FIN
      V                               V
+---------+                       +---------+
|  FIN    |                       |  CLOSE  |
| WAIT-1  |                       |  WAIT   |
+---------+                       +---------+
      |                               |
      V                               V
+---------+     +---------+     +---------+
|FINWAIT-2|     | CLOSING |     |LAST-ACK |
+---------+     +---------+     +---------+
      |               |               |
      V               V               V
+---------+       +---------+     +---------+
|TIME-WAIT|       | CLOSED  |     | CLOSED  |
+---------+       +---------+     +---------+

状态分类记忆:

阶段状态说明
初始CLOSED, LISTEN起点
握手SYN-SENT, SYN-RECEIVED三次握手过程
传输ESTABLISHED数据传输
挥手FIN-WAIT-1/2, CLOSING, CLOSE-WAIT, LAST-ACK关闭过程
结束TIME-WAIT, CLOSED收尾

4. 四次挥手(Four-Way Handshake)

TCP 是全双工的,每个方向独立关闭。关闭自己这一端的发送方向需要 FIN:

      主动关闭方 (A)                 被动关闭方 (B)
         ESTABLISHED                  ESTABLISHED
              |                            |
    ① FIN-WAIT-1                           |
              |── FIN, seq=u ───────────→  | CLOSE-WAIT
              |                            |
    ② FIN-WAIT-2                           |
              |←── ACK, seq=v, ack=u+1 ───| CLOSE-WAIT
              |                            |
              |                    (应用处理中)
              |                            |
    ③ TIME-WAIT                            | LAST-ACK
              |←── FIN, seq=w, ack=u+1 ───|
              |                            |
    ④ TIME-WAIT                            |
              |── ACK, seq=u+1, ack=w+1 ─→ | CLOSED
              |                            |
      2MSL 后 CLOSED

为什么是四次而不是三次?
因为 TCP 是全双工的。收到 FIN 只表示对方不再发送数据,本方还可以继续发送。本方也发 FIN 才表示本方的发送方向也关闭。中间的 ACK 和 FIN 通常不能合并——ACK 是立即回复的,而 FIN 需要等应用层调用 close()。


5. TIME_WAIT 状态详解

主动关闭方在发送最后一个 ACK 后进入 TIME_WAIT,持续 2MSL(Maximum Segment Lifetime,通常 2 分钟,实际实现中常为 30 秒到 2 分钟)。

TIME_WAIT 存在的两个原因(RFC 9293)

  1. 确保最后的 ACK 能被对方收到:如果最后的 ACK 丢失,被动方会重传 FIN,主动方还在 TIME_WAIT 就能重发 ACK。
  2. 让旧连接的所有段从网络中消失:防止旧连接的延迟段被新连接(相同四元组)误接收。

常见面试问题

Q: 大量 TIME_WAIT 怎么处理?

  • 调整内核参数:tcp_tw_reuse(复用 TIME_WAIT 连接)、tcp_tw_recycle(快速回收,已废弃)
  • 使用长连接代替短连接
  • 让客户端主动关闭(TIME_WAIT 在客户端,影响较小)

Q: 为什么 TIME_WAIT 是 2MSL?

  • 1 个 MSL 给最后的 ACK 到达对端,1 个 MSL 给可能重传的 FIN 回来。总共 2MSL 足够保证安全。

6. 同时打开与同时关闭

同时打开:双方同时发送 SYN,都进入 SYN-SENT,收到对方 SYN 后进入 SYN-RECEIVED 并回复 SYN+ACK。结果只建立一条连接。

同时关闭:双方同时发送 FIN,都进入 FIN-WAIT-1 → 收到 FIN 后进入 CLOSING → 收到 ACK 后进入 TIME-WAIT。


本篇要点

  • 三次握手:客户端发 SYN → 服务器回 SYN+ACK → 客户端回 ACK,双方交换初始序列号并确认收发能力
  • 三次握手不能省为两次:防止网络中延迟的旧 SYN 导致服务器错误建立连接
  • 四次挥手:每个方向独立关闭(FIN 和 ACK),全双工特性决定了不能合并
  • TIME_WAIT 持续 2MSL,作用:① 确保最后的 ACK 到达对方;② 让旧连接的延迟段从网络中消失
  • 客户端状态:CLOSED → SYN_SENT → ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
  • 服务端状态:CLOSED → LISTEN → SYN_RCVD → ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
  • 大量 CLOSE_WAIT 说明应用层没有正确关闭 socket(代码 bug);大量 TIME_WAIT 说明短连接过多
  • SYN Flood 攻击用伪造 IP 的 SYN 耗尽半连接队列,防御手段:SYN Cookie、防火墙限速、增大队列
上一页
TCP 简介与分层模型
下一页
TCP 可靠传输机制