深入理解 TCP 三次握手与四次挥手

196 阅读5分钟

1.前言

TCP(传输控制协议)是一种面向连接的、可靠的传输层协议,广泛应用于 HTTP、FTP、SSH 等网络通信。三次握手(Three-way Handshake)  用于建立连接,四次挥手(Four-way Handshake)  用于终止连接。理解这两个过程对网络编程、性能优化和故障排查至关重要。

本文将详细解析 TCP 三次握手和四次挥手 的流程、状态变化及常见问题。


2.TCP 三次握手(连接建立)

三次握手的目标是 同步双方的初始序列号(ISN) ,并确认双方的收发能力正常。

2.1 三次握手流程

最初,客户端处于closed状态,服务器处于listen状态

  1. 第一次握手(SYN)

    • 客户端 发送 SYN=1, seq=ISN(c),进入 SYN_SENT 状态。
    • 报文内容SYN=1, ACK=0, seq=ISN(c)
    • 作用:告知服务端,客户端希望建立连接,并指定初始序列号 ISN(c)
  2. 第二次握手(SYN + ACK)

    • 服务端 收到 SYN 后,回复 SYN=1, ACK=1, seq=ISN(s), ack=ISN(c)+1,进入 SYN_RCVD 状态。

    • 报文内容SYN=1, ACK=1, seq=ISN(s), ack=ISN(c)+1

    • 作用

      • 确认客户端的 SYNack=ISN(c)+1)。
      • 发送自己的初始序列号 ISN(s)
  3. 第三次握手(ACK)

    • 客户端 收到 SYN+ACK 后,发送 ACK=1, seq=ISN(c)+1, ack=ISN(s)+1,进入 ESTABLISHED 状态。
    • 服务端 收到 ACK 后,也进入 ESTABLISHED 状态。
    • 报文内容ACK=1, seq=ISN(c)+1, ack=ISN(s)+1
    • 作用:确认服务端的 SYN,连接正式建立。

2.2 为什么需要三次握手?

  • 防止历史重复连接初始化(避免旧的 SYN 报文干扰)。
  • 同步双方的初始序列号(ISN) ,确保数据按序传输。
  • 验证双方的收发能力(客户端能发 SYN,服务端能收 SYN 并回 ACK)。

面试题:为什么不是两次握手?
:> 第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。

第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。

第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。


3.TCP 四次挥手(连接终止

由于 TCP 是全双工的,关闭连接需要 双方各自发送 FIN 和 ACK,因此需要四次交互。

3.1 四次挥手流程

  1. 第一次挥手(FIN)

    • 主动关闭方(客户端)  发送 FIN=1, seq=u,进入 FIN_WAIT_1 状态。
    • 作用:通知服务端,客户端不再发送数据,但仍可接收数据。
  2. 第二次挥手(ACK)

    • 服务端 收到 FIN 后,回复 ACK=1, ack=u+1, seq=v,进入 CLOSE_WAIT 状态。
    • 客户端 收到 ACK 后进入 FIN_WAIT_2 状态。
    • 作用:确认客户端的 FIN,但服务端可能仍有数据要发送(半关闭状态)。
  3. 第三次挥手(FIN)

    • 服务端 发送完剩余数据后,发送 FIN=1, ACK=1, seq=w, ack=u+1,进入 LAST_ACK 状态。
    • 作用:通知客户端,服务端也准备关闭连接。
  4. 第四次挥手(ACK)

    • 客户端 收到 FIN 后,回复 ACK=1, ack=w+1, seq=u+1,进入 TIME_WAIT 状态,等待 2MSL(Maximum Segment Lifetime)后关闭。
    • 服务端 收到 ACK 后立即进入 CLOSED 状态。
    • 作用:确保服务端收到最后的 ACK,防止 FIN 重传。

3.2 为什么需要四次挥手?

  • TCP 是全双工的,双方需独立关闭自己的数据流。
  • 服务端可能在 FIN 前仍有数据要发送(CLOSE_WAIT 阶段)。
  • TIME_WAIT 确保最后一个 ACK 可靠到达,避免旧报文干扰新连接。

面试题:为什么 TIME_WAIT 需要等待 2MSL?

  1. 确保最后一个 ACK 到达服务端(如果丢失,服务端会重传 FIN)。
  2. 让网络中残留的旧报文失效,避免影响后续新连接。

4.常见问题

4.1 三次握手的 SYN 洪泛攻击

  • 攻击方式:攻击者发送大量 SYN 但不回复 ACK,耗尽服务端资源。

  • 防御方法

    • SYN Cookie(不存储半连接状态)。
    • 限制 SYN 请求速率。

4.2 大量 CLOSE_WAIT 状态的连接

  • 原因:服务端未及时调用 close(),导致连接长期处于 CLOSE_WAIT
  • 解决方案:检查代码是否漏掉 socket.close(),或调整 SO_LINGER 参数。

4.3 TIME_WAIT 过多影响性能

  • 现象:高并发短连接时,端口被 TIME_WAIT 占用,无法复用。

  • 优化方法

    • 启用 SO_REUSEADDR 复用 TIME_WAIT 端口。
    • 调整 tcp_tw_reuse(Linux 内核参数)。


5. 总结

阶段三次握手(建立连接)四次挥手(关闭连接)
目的同步初始序列号,确认通信能力双方独立关闭数据流,确保可靠终止
交互次数3 次(SYN → SYN+ACK → ACK)4 次(FIN → ACK → FIN → ACK)
关键状态SYN_SENTSYN_RCVDFIN_WAIT_1CLOSE_WAITTIME_WAIT
典型问题SYN 洪泛攻击TIME_WAIT 过多、CLOSE_WAIT 堆积

理解 TCP 握手与挥手机制,有助于优化网络编程、排查连接问题。建议结合 Wireshark 抓包 实践分析,加深印象。


参考资料

  • RFC 793(TCP 协议标准)
  • 《TCP/IP 详解 卷1:协议》
  • Linux net.ipv4.tcp_tw_reuse 参数说明

希望这篇博客对你有所帮助!欢迎讨论与指正。 🚀