TCP连接管理:三次握手与四次挥手详解

TCP(Transmission Control Protocol)是一种面向连接可靠的传输层协议。在数据传输前必须建立连接,传输结束后必须释放连接。这个过程分别由三次握手(Three-Way Handshake)和四次挥手(Four-Way Handshake)完成。

1. TCP报文段首部关键字段

理解握手和挥手前,先记住以下6个关键控制位(flags):

字段 含义 作用场景
SYN 同步序列号(Synchronize) 发起连接请求
ACK 确认(Acknowledgment) 确认收到对方报文
FIN 结束(Finish) 请求释放连接
RST 复位(Reset) 异常中断连接
PSH 推送(Push) 尽快交付应用层
URG 紧急(Urgent) 紧急数据

另外两个重要字段:

  • seq(Sequence Number):本方发送数据的起始序号
  • ack(Acknowledgment Number):期待收到的对方下一个字节的序号(即已确认收到 ack-1 之前的字节)
2. 三次握手(建立连接)

目的:双方确认彼此的发送能力和接收能力正常,并协商初始序号(ISN)。

过程图示:

客户端                          服务端
   |   SYN (seq=x)                  |
   |------------------------------>|
   |   SYN+ACK (seq=y, ack=x+1)      |
   |<------------------------------|
   |   ACK (seq=x+1, ack=y+1)        |
   |------------------------------>|

详细步骤:

  1. 第一次握手(SYN)
    客户端发送 SYN 报文:

    • SYN=1
    • seq = x(客户端随机初始序号)
    • ACK=0(此时还没确认)
      客户端进入 SYN_SENT 状态。
      → 告诉服务端:“我想和你建立连接,我的初始序号是 x”
  2. 第二次握手(SYN+ACK)
    服务端收到 SYN 后回复:

    • SYN=1, ACK=1
    • seq = y(服务端随机初始序号)
    • ack = x+1(确认收到客户端的 SYN,期待下一个序号为 x+1)
      服务端进入 SYN_RCVD 状态。
      → 告诉客户端:“我同意建立连接,我的初始序号是 y,我已收到你的 SYN”
  3. 第三次握手(ACK)
    客户端收到 SYN+ACK 后发送最终确认:

    • SYN=0, ACK=1
    • seq = x+1
    • ack = y+1
      双方都进入 ESTABLISHED 状态,可以开始传输数据。

为什么是三次而不是两次?
两次握手只能确认客户端→服务端的单向通信能力,无法确认服务端→客户端的通道是否正常(旧的重复 SYN 可能导致服务端误以为是新连接)。三次握手确保双方都能正常收发。

3. 四次挥手(释放连接)

目的:确保双方都有机会优雅地关闭连接,数据都能可靠送达(半关闭特性:支持单方向先关闭)。

过程图示(假设客户端主动关闭):

客户端                          服务端
   |   FIN (seq=a)                  |
   |------------------------------>|
   |   ACK (ack=a+1)                 |
   |<------------------------------|
   |                                |  (服务端可能还有数据要发)
   |   (可能收到数据)              |
   |<------------------------------|
   |   FIN (seq=b)                  |
   |<------------------------------|
   |   ACK (ack=b+1)                 |
   |------------------------------>|

详细步骤:

  1. 第一次挥手(客户端发送 FIN)
    客户端数据发送完毕,发送 FIN 报文:

    • FIN=1, seq=a
      客户端进入 FIN_WAIT_1 状态。
      → “我发完了,你还有数据要发吗?”
  2. 第二次挥手(服务端回复 ACK)
    服务端收到 FIN,立刻回复确认:

    • ACK=1, ack=a+1
      服务端进入 CLOSE_WAIT 状态。
      客户端收到后进入 FIN_WAIT_2 状态。
      → “我收到你发完的通知了,但我要处理完剩余数据”

    注意:此时连接处于半关闭状态,客户端不再发送数据,但仍能接收服务端数据。

  3. 第三次挥手(服务端发送 FIN)
    服务端处理完所有数据后,发送自己的 FIN:

    • FIN=1, seq=b
      服务端进入 LAST_ACK 状态。
      → “我也发完了,可以关闭了”
  4. 第四次挥手(客户端回复 ACK)
    客户端收到服务端 FIN 后回复最终确认:

    • ACK=1, ack=b+1
      客户端进入 TIME_WAIT 状态,等待 2MSL(最大报文生存时间,通常 1-4 分钟)后才完全关闭。
      服务端收到 ACK 后立即进入 CLOSED 状态。

为什么客户端要 TIME_WAIT 等待 2MSL?

  • 确保最后的 ACK 能到达服务端(如果丢失,服务端会重发 FIN,客户端可重新确认)
  • 防止旧连接的延迟报文干扰新连接(同一四元组的旧报文在网络中存活不超过 MSL)

为什么是四次而不是三次?
因为 TCP 是全双工的,关闭需要分别关闭两个方向。服务端收到客户端 FIN 后可能还有数据要发,不能立即关闭,必须等自己也准备好再发 FIN。

4. 常见状态变迁总结(客户端主动关闭)
客户端状态 服务端状态
CLOSED CLOSED
SYN_SENT LISTEN
ESTABLISHED SYN_RCVD
FIN_WAIT_1 ESTABLISHED
FIN_WAIT_2 CLOSE_WAIT
TIME_WAIT LAST_ACK
CLOSED CLOSED
5. 常见面试延伸问题
  • 为什么初始序号 ISN 要随机?→ 防止历史旧连接的报文被误认为是新连接的数据。
  • 如果第三次握手丢失会怎样?→ 服务端超时重发 SYN+ACK,客户端重新发送第三次 ACK。
  • 大量 TIME_WAIT 如何处理?→ 调小 time_wait 时间、开启 tcp_tw_reuse/recycle(慎用)。
  • SYN Flood 攻击?→ 攻击者发送大量 SYN 不完成第三次握手,耗尽服务端半连接队列。防御:syn cookies、增加 backlog 等。

希望这个详解清晰易懂!如果需要结合 Wireshark 抓包示例、状态机图或其他深入点(如同时打开、同时关闭),随时告诉我。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐