一文看懂 | TCP三次握手和四次挥手

511 阅读5分钟

前言

TCP(传输控制协议)是一种全双工通信的网络传输协议。

这意味着在 TCP 连接中,通信双方可以同时进行数据的发送和接收,无需等待对方的响应才能继续传输。

彻底理解 TCP 协议需要搞清楚 状态机的变化和时机

其中一些英语简写的示意如下:

  • SYN(Synchronize):可以理解为报文,用于连接建立。
    • SYN_SENT(Synchronize Sent):报文已发送。
    • SYN_RCVD(Synchronize Received):报文已接收。
  • FIN(Finish):请求关闭连接。
    • FIN_WAIT_1(Finish Wait 1):客户端关闭请求已发起,等待回执。
    • FIN_WAIT_2(Finish Wait 2):回执已收到,等待服务端发起关闭连接请求。此时客户端仍可接收数据,但不能发送。
    • TIME_WAIT(Time Wait):服务端关闭请求已收到,发送回执,等待超时断开连接。
  • ACK(Acknowledgment):可以理解为确认,表示已成功接收数据,用于发送回执。
    • LAST_ACK(Last Acknowledgment):最后一次确认等待状态。
  • ESTABLISHED:连接已建立。
  • CLOSED:连接已关闭。

一、TCP三次握手

TCP连接过程:

  • 客户端 发SYN(x)
  • 服务端 收+发 SYN+ACK(x+1, y)
  • 客户端 收+发 ACK(y+1)
  • 服务端 收

image.png

客户端状态变更:

CLOSED = 发 => SYN_SENT = 收+发 => ESTABLISHED (我发,对方 收+发,我 收+发)

服务端状态变更:

LISTEN = 收+发 => SYN_RCVD = 收 => ESTABLISHED (我 收+发,对方 收+发,我收)

双方都要验证:

  • 我发的对方能收到,对方发的我能收到(我可以发送、接收,对方可以接收、发送)
  • 并且保持序列号同步,防止因网络延迟导致的序列号混乱(如旧连接的幽灵包)。

对于客户端来说:

  • CLOSED = 发=> SYN_SENT:我可以发送
  • SYN_SENT = 收+发 => ESTABLISHED:对方可以接收、发送,我可以接收

对于服务端来说:

  • LISTEN = 收+发 => SYN_RCVD :对方可以发送,我可以接收、发送
  • SYN_RCVD = 收 => ESTABLISHED:对方可以接收

三次握手是数学上的最小可靠解

  • 通过三次消息交换,实现四次能力验证(双方各验证两次)。
  • 通过序列号绑定,确保双方对初始状态达成一致。
  • 通过状态机转换,确保任何异常都能被检测并恢复(如超时回退到 CLOSED/LISTEN)。

二、TCP四次挥手

image.png

TCP断开连接过程:

  • 客户端 发FIN(x)
  • 服务端 收+发 ACK(x+1)
  • 客户端 收
  • 服务端 发 FIN(y)
  • 客户端 收+发 ACK(y+1)
  • 服务端 收

客户端状态变更:

ESTABLISHED = 发 => FIN_WAIT_1 = 收 => FIN_WAIT_2 = 收+发 => TIME_WAIT = 超时 => CLOSED

服务端状态变更:

ESTABLISHED = 收+发 => CLOSE_WAIT = 发 => LAST_ACK = 收 => CLOSED

双方都要验证:

  • 我发的终止信号对方能收到
  • 对方发的终止信号我能收到
  • 确保所有数据都已完整传输(避免数据丢失)

对于客户端来说:

  1. ESTABLISHED → FIN_WAIT_1

    • 动作:发FIN(x)
    • 验证点:我可以主动请求关闭发送方向 → 若发送失败,则保持ESTABLISHED继续通信。
  2. FIN_WAIT_1 → FIN_WAIT_2

    • 动作:收ACK(x+1)
    • 验证点:对方已接收关闭请求,并回执我ACK(x+1) → 此时客户端仍可接收数据,进入“半关闭”状态。
  3. FIN_WAIT_2 → TIME_WAIT

    • 动作:收FIN(y) + 发ACK(y+1)
    • 验证点:
      • 对方也请求关闭连接(通过FIN包验证)。
      • 我可以确认对方的关闭请求(通过ACK包验证)。
  4. TIME_WAIT → CLOSED

    • 动作:等待2倍的MSL时间(MSL,报文最大生存时间,通常约 2 分钟)
    • 验证点:确保所有网络延迟包都已消失
      → 防止旧连接的延迟包干扰新连接。

对于服务端来说:

  1. ESTABLISHED → CLOSE_WAIT

    • 动作:收FIN(x) + 发ACK(x+1)
    • 验证点:
      • 对方已请求关闭发送方向(通过FIN包验证)。
      • 我可以确认对方的关闭请求(通过ACK包验证)。
        → 此时服务端需检查是否还有数据要发送,若有则继续发送。
  2. CLOSE_WAIT → LAST_ACK

    • 动作:发FIN(y)
    • 验证点:我可以主动请求关闭接收方向
      → 表明服务端已无数据要发送,准备关闭连接。
  3. LAST_ACK → CLOSED

    • 动作:收ACK(y+1)
    • 验证点:对方已确认我的关闭请求
      → 此时服务端完全关闭连接,释放所有资源。

四次挥手的数学必然性

  1. 最小消息交换次数
    双方各需发送FIN和接收ACK,共四次消息,无法简化。

  2. 状态机的完整性

    • 客户端通过TIME_WAIT状态防止最后一个ACK丢失导致服务器无法关闭。
    • 服务器通过CLOSE_WAIT状态确保所有数据发送完毕后再关闭。
  3. 防止幽灵包干扰
    TIME_WAIT状态保持2MSL时间,确保:

    • 本次连接的所有包都已从网络中消失。
    • 相同IP和端口的新连接不会收到旧连接的延迟包。

三、四次挥手 vs 三次握手

阶段消息交换核心目的状态机保障
三次握手3次同步初始序列号,验证双向通信能力防止旧连接幽灵包,资源预分配
四次挥手4次可靠关闭双向连接,确保数据完整性防止FIN/ACK丢失,幽灵包清理

四、关键机制补充

  1. 半关闭状态(Half-Closed)

    • 当客户端处于FIN_WAIT_2,服务端处于CLOSE_WAIT时,连接处于半关闭状态:
      • 客户端停止发送,但仍可接收。
      • 服务端仍可发送,但需主动发起FIN关闭接收方向。
  2. TIME_WAIT的意义

    • 确保最后一个ACK成功到达服务器(若丢失,服务器会重传FIN)。
    • 让旧连接的所有包在网络中自然消亡,避免影响新连接。
  3. 异常处理

    • 若客户端在TIME_WAIT超时前收到服务器重传的FIN,会重新发送ACK并重置计时器。
    • 若服务器未收到ACK,会重传FIN(默认重试8次,约120秒)。

四次挥手是TCP可靠性的终极体现:

  • 通过四次消息交换,实现双向连接的有序关闭。
  • 通过状态机和超时机制,确保任何异常都能被妥善处理。
  • 通过TIME_WAIT状态,从根本上杜绝了新旧连接的数据包混淆。