TCP三次握手

在双方开始正式传输 HTTP 数据之前,必须先通过三次握手来同步双方的序列号(seq)和确认号(ack),并协商 TCP 窗口大小。通俗地说,就是为了**确认双方的“发送”和“接收”能力都是正常的**。

#status / growing #type / concept #resource / typescript

[!info] related notes

TCP三次握手

在双方开始正式传输 HTTP 数据之前,必须先通过三次握手来同步双方的序列号(seq)和确认号(ack),并协商 TCP 窗口大小。通俗地说,就是为了确认双方的“发送”和“接收”能力都是正常的

我为您拆解一下这三次握手的具体过程:

1. 第一次握手(客户端 -> 服务端)

  • 动作:客户端向服务端发送一个带有 SYN=1(同步序列编号)标志位的数据包,并随机生成一个初始序列号 seq = x。发送后,客户端进入 SYN_SENT 状态。
  • 潜台词“服务端你好,我想跟你建立连接,你能听到我说话吗?”

2. 第二次握手(服务端 -> 客户端)

  • 动作:服务端收到这个 SYN 数据包后,知道客户端要建立连接。于是它向客户端发送一个带有 SYN=1ACK=1(确认标志)的数据包。其中确认号 ack = x + 1(表示收到了客户端的序列号),同时服务端也随机生成自己的初始序列号 seq = y。发送后,服务端进入 SYN_RCVD 状态。
  • 潜台词“我听到了!我也准备好跟你建立连接了,你能听到我说话吗?”
  • (注:此时服务端确认了客户端的发送能力和自己的接收能力是正常的)

3. 第三次握手(客户端 -> 服务端)

  • 动作:客户端收到服务端的 SYN+ACK 包后,知道服务端同意连接了。于是它向服务端发送一个带有 ACK=1 标志的确认包。确认号 ack = y + 1,序列号 seq = x + 1。发送后,客户端进入 ESTABLISHED(已连接)状态;服务端收到这个包后,也进入 ESTABLISHED 状态。
  • 潜台词“我也听到了!我们的通信没问题,准备开始传数据吧。”
  • (注:此时客户端确认了服务端的发送能力和自己的接收能力,服务端也确认了客户端的接收能力正常)

面试高频追问防守:为什么必须是三次,两次不行吗?

如果只握手两次,会存在一个致命的漏洞:防止历史失效的连接请求报文段突然又传送到了服务端,导致资源浪费。

假设客户端发出的第一个 SYN 包在网络节点中滞留了,客户端等不到响应,超时后又发了一个新的 SYN 包,完成了两次握手并传完数据断开了。 此时,那个滞留的“旧 SYN 包”突然到达了服务端。如果是“两次握手”,服务端只要收到 SYN 就会直接建立连接并分配资源,然后一直傻等着客户端发数据。但客户端现在根本没打算发数据,服务端的端口和内存资源就被白白占用(这也叫 SYN 泛洪攻击的原理基础)。

而在“三次握手”机制下,服务端收到旧的 SYN 包回复 SYN+ACK 后,客户端一看确认号不对(是过期的),就会发一个 RST 报文让服务端中止连接,从而完美避开这个问题。

创建于 2026/3/12 更新于 2026/5/27