← 返回题目列表

TCP 为什么要三次握手?两次不行吗?

高频 中等 第 12 / 30 题 更新于 2026/07/28
TCP三次握手网络

简化版

三次握手是为了让双方都确认「我能发、你能收;你能发、我能收」这两条链路都通,同时同步各自的初始序列号(ISN)。两次不行,因为两次握手结束时,服务端无法确认客户端到底有没有收到自己发的 SYN+ACK,也无法防止历史失效的连接请求造成错误连接。

详细版

三次握手的过程

  1. 第一次:客户端发 SYN,带上自己的初始序列号 seq=x——「我想建连,我的序号从 x 开始」。
  2. 第二次:服务端回 SYN + ACKack=x+1(确认收到客户端的 x),同时带自己的序号 seq=y——「收到你的了,我的序号从 y 开始」。
  3. 第三次:客户端回 ACKack=y+1——「也收到你的了」。

为什么必须三次,可以从「双方各自要确认什么」推:

  • 第 1、2 次之后,客户端确认了:我发的对方收到了(收到 SYN+ACK),双向都通。
  • 但此时服务端只知道「我发出了 SYN+ACK」,不知道客户端有没有收到
  • 第 3 次 ACK,就是客户端告诉服务端「你的我收到了」——至此服务端才确认双向都通。

所以三次是让双方都完成确认的最小次数:SYN 和 ACK 各需要一来一回,共 4 个动作,中间服务端的 ACK 和 SYN 可以合并成一个包,就成了三次。

完整版教学

一、握手的本质:确认「双向都能通」

TCP 是全双工、可靠传输,建连的目标是确保两个方向的通道都畅通。「通道畅通」需要确认四件事:

  1. 客户端能发(→ 服务端收到 SYN,确认①)
  2. 服务端能收(同上)
  3. 服务端能发(→ 客户端收到 SYN+ACK,确认③)
  4. 客户端能收(同上)

第二次握手一次性确认了 ①②③④ 中客户端视角的部分——客户端确认「双向都通」。但服务端视角里,「客户端能不能收到我的包(③④)」还没被验证。第三次握手补上这个确认。三次,恰好让双方都验证完双向链路。

二、两次为什么不行——两个致命问题

问题一:服务端无法确认自己的包被收到。 如果只握两次,服务端发完 SYN+ACK 就认为连接建立、开始发数据。但万一这个 SYN+ACK 在网络里丢了,客户端根本不知道连接建立了,服务端却在傻傻发数据——单方面建连,浪费资源。

问题二:历史失效连接请求造成错误连接(更经典)。 设想客户端发的一个旧的、在网络里滞留了很久的 SYN 突然到达服务端:

  • 两次握手:服务端收到就直接建连、分配资源,但客户端其实早不想连了(那是个过期请求)→ 服务端凭空建了个没人用的连接,白占资源。
  • 三次握手:服务端回 SYN+ACK 后,客户端发现「我没发起这个连接」,不会回第三次 ACK(或回 RST),连接建立不起来 → 避免了错误连接。

记忆点:第三次 ACK 的核心价值,就是给客户端一次「否决历史失效请求」的机会。这是很多人只记得「确认收发能力」而漏掉的关键点。

三、为什么要同步初始序列号(ISN)

TCP 靠序列号实现可靠传输(排序、去重、确认、重传)。握手时双方交换各自的 ISN,之后的数据都基于它编号。

ISN 还不能固定(比如都从 0 开始),而是随机生成的。原因:如果 ISN 可预测,一是旧连接的残留数据包可能被误认为新连接的合法数据(序号撞上),二是攻击者能伪造序列号劫持连接。随机 ISN 同时解决了「历史数据混淆」和「安全」两个问题。

四、延伸:SYN Flood 攻击

三次握手有个可被利用的弱点:服务端收到第一次 SYN 后,会分配资源、把连接放进半连接队列,等待第三次 ACK。攻击者用伪造源地址狂发 SYN 但从不回 ACK,就能把半连接队列塞满,正常用户连不进来——这就是 SYN Flood

常见缓解:

  • SYN Cookie:服务端先不分配资源,把连接信息编码进序列号发回去,等第三次 ACK 回来再校验重建,队列不会被占满;
  • 调大半连接队列、缩短等待超时;
  • 边界设备限速、过滤异常源。

五、常见误区

  • ❌ 只答「确认双方收发能力」——漏了「防止历史失效连接」这个关键原因。
  • ❌ 以为握手是为了传数据——握手只建连、同步 ISN,不携带应用数据。
  • ❌ 以为四次也行、越多越可靠——三次是让双方都确认的最小次数,多余的浪费。(四次挥手是断连,别和建连混。)
  • ❌ 以为 ISN 从 0 开始——是随机的,防混淆和劫持。

六、常见误区与追问

考点正确口径
第一次客户端发 SYN,证明客户端发送能力
第二次服务端回 SYN+ACK,证明服务端收发能力
第三次客户端回 ACK,证明客户端接收能力并确认服务端 SYN
Client -> SYN(x)
Server -> SYN(y), ACK(x+1)
Client -> ACK(y+1)
connection established

三次握手要确认的是双向收发能力和初始序列号,不只是“打个招呼”。

  • 误区:两次握手也能确认双方可通信。 两次后服务端不知道客户端是否收到了自己的 SYN,无法确认客户端接收能力。
  • 误区:三次握手只是为了浪费一次 RTT。 第三次 ACK 能避免历史 SYN 导致服务端误建连接,并确认服务端序列号。
  • 误区:ISN 可以固定从 0 开始。 ISN 应随时间变化并具备随机性,降低旧报文混淆和安全风险。
  • 追问:为什么第二次 SYN 和 ACK 能合并? 服务端既确认客户端 SYN,又要发送自己的 SYN,同一个报文可同时带两个标志。
  • 追问:SYN Flood 利用了什么? 攻击者发送大量 SYN 不完成第三次握手,让服务端半连接状态堆积。
  • 追问:握手完成后双方状态是什么? 客户端第三次 ACK 发出后进入 ESTABLISHED,服务端收到 ACK 后进入 ESTABLISHED。

七、加强记忆

三次握手让双方都确认「双向链路畅通」并同步随机初始序列号。两次不行,一是服务端无法确认自己的 SYN+ACK 被收到,二是无法用第三次 ACK 否决「历史失效的连接请求」而导致错误建连。它的副作用是半连接队列可被 SYN Flood 攻击,用 SYN Cookie 等缓解。