好的,TCP的三次握手与四次挥手是理解网络通信和连接管理的核心。下面我将以清晰、结构化、结合图示的方式为你详细解析。

核心概念

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。“连接”的建立与终止是可靠传输的前提,这个过程就是通过握手挥手来完成的。


一、TCP三次握手(建立连接)

目标:在客户端和服务端之间建立可靠的连接,同步双方的初始序列号,并交换参数(如MSS窗口大小)。

状态变迁

  • 客户端CLOSED -> SYN-SENT -> ESTABLISHED
  • 服务端CLOSED -> LISTEN -> SYN-RECEIVED -> ESTABLISHED

过程详解

客户端 (Client)                                    服务端 (Server)
    |                                                    |
    |                  1. SYN                            |
    |              Seq = x (随机)                        |
    |              Flags: SYN=1                          |
    |--------------------------------------------------->|
    |                                                    | 状态:LISTEN
    |                  2. SYN + ACK                      |
    |              Seq = y (随机)                        |
    |              Ack = x + 1                           |
    |              Flags: SYN=1, ACK=1                   |
    |<---------------------------------------------------|
    |                                                    | 状态:SYN-RCVD
    |                  3. ACK                            |
    |              Seq = x + 1                           |
    |              Ack = y + 1                           |
    |              Flags: ACK=1                          |
    |--------------------------------------------------->|
    |                                                    | 状态:ESTABLISHED
状态:ESTABLISHED                                         |
    |                                                    |
    |               【连接建立,开始数据传输】              |
    |====================================================>|

每一步的深层含义

  1. 第一次握手 (SYN)

    • 客户端发送一个SYN包(SYN标志位设为1)。
    • 选择一个初始序列号 x(随机生成)。
    • 意义:客户端告诉服务端:“我想和你建立连接,我的起始数据包序号是 x。”
  2. 第二次握手 (SYN + ACK)

    • 服务端收到SYN包后,如果同意连接,则回复一个SYN+ACK包。
    • SYN标志位和ACK标志位均设为1。
    • 服务端也选择一个自己的初始序列号 y
    • 确认号 Ack 设为 x + 1。这表示服务端确认收到了客户端的SYN,并期望客户端下一个数据包的序号是 x+1
    • 意义:服务端告诉客户端:“我收到了你的连接请求,我同意建立连接。我的起始数据包序号是 y,并确认了你的序号 x。”
  3. 第三次握手 (ACK)

    • 客户端收到SYN+ACK包后,必须向服务端发送一个ACK包进行确认。
    • ACK标志位设为1。
    • 序列号 Seq 设为 x + 1(因为第一次握手的SYN消耗了一个序号)。
    • 确认号 Ack 设为 y + 1。这表示客户端确认收到了服务端的SYN,并期望服务端下一个数据包的序号是 y+1
    • 意义:客户端告诉服务端:“我收到了你的确认,连接已经建立。”

为什么是三次,而不是两次?

核心答案:为了防止已失效的连接请求报文突然又传到了服务器,导致资源浪费和错误。

  • 场景:客户端发送了一个SYN包,由于网络拥堵迟迟未到。客户端超时重发了一个新的SYN并成功建立了连接。之后,那个旧的SYN包终于到达了服务器。
  • 如果是两次握手:服务器收到旧SYN就会直接回复SYN+ACK并进入ESTABLISHED状态,开始等待客户端发送数据。这会导致服务器为一个不存在的连接预留资源,造成浪费。
  • 三次握手的作用:在上述场景中,服务器会回复SYN+ACK,但客户端知道这不是自己当前期望的连接,会回复一个RST(复位)包,让服务器关闭这个无效的连接请求。三次握手确保了双方都确认了自己和对方的收发能力是正常的

二、TCP四次挥手(终止连接)

目标:安全、优雅地关闭一个TCP连接。TCP连接是全双工的,每个方向必须单独关闭。

状态变迁

  • 主动关闭方(图中客户端):ESTABLISHED -> FIN-WAIT-1 -> FIN-WAIT-2 -> TIME-WAIT -> CLOSED
  • 被动关闭方(图中服务端):ESTABLISHED -> CLOSE-WAIT -> LAST-ACK -> CLOSED

过程详解

客户端 (主动关闭)                                  服务端 (被动关闭)
    |                                                    |
    |               【数据传输完成】                      |
    |====================================================>|
    |                                                    |
    |                  1. FIN                            |
    |              Seq = u (已发送数据的最后一个序号+1)   |
    |              Flags: FIN=1                          |
    |--------------------------------------------------->|
    |                                                    | 状态:CLOSE-WAIT
    |                  2. ACK                            |
    |              Seq = v                               |
    |              Ack = u + 1                           |
    |              Flags: ACK=1                          |
    |<---------------------------------------------------|
    | 状态:FIN-WAIT-2                                    |
    |                                                    | (服务端可能还有数据要发送)
    |                                                    | ... 发送剩余数据 ...
    |                                                    |
    |                  3. FIN                            |
    |              Seq = w (可能等于v)                   |
    |              Ack = u + 1                           |
    |              Flags: FIN=1, ACK=1                   |
    |<---------------------------------------------------|
    |                                                    | 状态:LAST-ACK
    |                  4. ACK                            |
    |              Seq = u + 1                           |
    |              Ack = w + 1                           |
    |              Flags: ACK=1                          |
    |--------------------------------------------------->|
    | 状态:TIME-WAIT (等待 2MSL)                         | 状态:CLOSED
    | 等待 2MSL 超时后                                      |
    | 状态:CLOSED                                        |
    |                                                    |

每一步的深层含义

  1. 第一次挥手 (FIN)

    • 主动关闭方(客户端)发送一个FIN包,表示自己没有数据要发送了。
    • 意义:“我(客户端)的数据发完了,准备关闭我这边到你的连接。”
  2. 第二次挥手 (ACK)

    • 被动关闭方(服务端)收到FIN后,立即回复一个ACK包,确认收到关闭请求。
    • 此时,TCP连接处于半关闭状态。客户端到服务端的连接关闭,但服务端到客户端的方向仍然可以发送数据
    • 意义:“好的,我知道你要关闭了。”
  3. 第三次挥手 (FIN)

    • 被动关闭方(服务端)将剩余的数据发送完毕后,也发送一个FIN包。
    • 意义:“我(服务端)的数据也发完了,准备关闭我这边到你的连接。”
  4. 第四次挥手 (ACK)

    • 主动关闭方(客户端)收到FIN后,发送最后一个ACK包进行确认。
    • 然后进入 TIME-WAIT 状态,等待 2MSL (最长报文段寿命的两倍时间)后,才彻底关闭连接。
    • 意义:“收到,我们都可以关闭了。”

关键问题与设计考量

  1. 为什么是四次挥手?

    因为TCP是全双工的,两个方向需要独立关闭。当一方说“我发完了”(FIN),另一方可能还有数据要发送。所以先回复一个ACK确认关闭请求,等自己数据发完后再发送自己的FIN。因此ACKFIN通常是分开发送的,导致需要四步。

  2. 为什么主动关闭方需要 TIME-WAIT 状态,并且要等待 2MSL

    两个主要目的

    • 可靠地终止连接:确保最后一个ACK能到达对方。如果这个ACK丢失,被动关闭方会超时重传它的FIN。主动关闭方在TIME-WAIT状态下可以收到这个重传的FIN并再次发送ACK
    • 让旧连接的所有报文在网络中消逝:防止之前延迟的、属于这个连接的报文段干扰新的、相同的四元组(源IP、源端口、目的IP、目的端口)连接。等待2MSL足以让任何方向上的报文最多存活MSL秒后被丢弃。
  3. 如果已经建立了连接,但客户端突然故障(崩溃)怎么办?

    TCP有一个保活机制。服务端会定期发送保活探测报文。如果连续多个探测都没有响应,则判定连接已死,主动关闭它。

总结对比

特性 三次握手 四次挥手
目的 建立可靠连接,同步序列号 安全、优雅地终止全双工连接
次数 3次报文交换 4次报文交换
关键标志位 SYN, ACK FIN, ACK
特殊状态 SYN-SENT, SYN-RCVD TIME-WAIT, CLOSE-WAIT
设计原因 防止失效连接请求,验证双向通信能力 应对全双工关闭的异步性,保证关闭可靠性

理解这两个过程,是掌握TCP协议可靠传输机制的基础,也是排查网络连接问题(如连接失败、端口占用、大量TIME_WAIT等)的关键。

Logo

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

更多推荐