目录
Please enable Javascript to view the contents

TCP 三次握手四次挥手备忘

 ·  ☕ 2 分钟

重要

三次握手建立连接,四次挥手释放连接。握手多一次是历史遗留连接的防御,挥手多一次是因为 TCP 全双工——双方各需要一个 FIN + ACK。

1. 标志位速查

标志含义
SYN同步序号,建立连接时使用
ACK确认号有效(连接建立后所有报文都必须置 1)
FIN发送方数据已发送完毕,请求释放连接
seq本报文段第一个数据字节的序号
ack期望收到对方下一个字节的序号

2. 三次握手

1
2
3
4
5
6
7
8
9
Client                                Server
  |                                     |
  |--- SYN=1, seq=x ---------------->   | SYN_SENT → SYN_RCVD
  |                                     |
  |<-- SYN=1, ACK=1, ack=x+1, seq=y -- | SYN_RCVD
  |                                     |
  |--- ACK=1, ack=y+1 -------------->   | ESTABLISHED
  |                                     |
ESTABLISHED                         ESTABLISHED
次数方向内容目的
1C → SSYN, seq=x请求建立连接
2S → CSYN+ACK, seq=y, ack=x+1确认收到,同时发起反向连接请求
3C → SACK, ack=y+1确认服务端的连接请求

为什么是三次而非两次

两次握手的漏洞:客户端发 SYN-1,网络超时重发 SYN-2。连接建立、通信完成、释放后,SYN-1 才抵达服务端。服务端回 SYN+ACK,认为连接已建立,但客户端已不认这个连接——造成服务端资源浪费。

三次握手中,SYN-1 到达后服务端回 SYN+ACK,客户端不会再回 ACK,服务端收不到确认则不会建立连接。

3. 四次挥手

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Client                                Server
  |                                     |
  |--- FIN=1, seq=x ---------------->   | FIN_WAIT_1 → CLOSE_WAIT
  |                                     |
  |<-- ACK=1, ack=x+1, seq=y -------- | FIN_WAIT_2 → CLOSE_WAIT
  |                                     |
  |<-- FIN=1, ACK=1, ack=x+1, seq=z-- | FIN_WAIT_2 → LAST_ACK
  |                                     |
  |--- ACK=1, ack=z+1 -------------->   | TIME_WAIT → CLOSED
  |                                     |
TIME_WAIT (2MSL) → CLOSED           CLOSED
次数方向内容目的
1C → SFIN, seq=x客户端不再发送数据
2S → CACK, ack=x+1确认收到 FIN
3S → CFIN+ACK, seq=z, ack=x+1服务端也发完数据,请求关闭
4C → SACK, ack=z+1确认服务端 FIN,进入 TIME_WAIT

为什么挥手多一次

TCP 是全双工——双方各自独立关闭。服务端收到 FIN 后,可能还有数据未发完,所以 ACKFIN 分开发送,多了一次。

为什么 TIME_WAIT 要等 2MSL

原因说明
可靠关闭最后一条 ACK 可能丢失,服务端重发 FIN,客户端在 2MSL 内还能收到并重发 ACK
清除旧报文让本次连接的所有残余报文从网络中消失,防止干扰下一个使用相同端口的新连接

参考

分享

Hex
作者
Hex
CloudNative Developer