技术

TCP 三次握手:为什么恰好是三次

字号
TCP 三次握手:为什么恰好是三次

TCP 建立连接需要客户端与服务器交换三个报文,这就是常说的「三次握手」。本文只回答一个问题:为什么恰好是三次,两次不行吗?

一、三次握手做了什么

设客户端的初始序号为 x,服务器的初始序号为 y:

客户端 → 服务器   SYN, seq = x
服务器 → 客户端   SYN+ACK, seq = y, ack = x + 1
客户端 → 服务器   ACK, ack = y + 1

两个关键点:

  1. SYN 报文消耗一个序号。所以服务器确认的是 x + 1,表示「你发的 SYN 我收到了,下一个字节从 x+1 开始」。
  2. 第三次握手的 ACK 可以携带数据,也可以不携带——不携带数据时它不消耗序号。

二、为什么两次不够

RFC 793 在 3.4 节(Why Three Segments?)给出了权威解释,核心是两点:

第一,双方都要确认对方的初始序号。 TCP 是全双工的,序号是可靠传输的基石。客户端发 SYN 告诉服务器「我的序号从 x 起」,服务器必须确认;服务器的 SYN 告诉客户端「我的序号从 y 起」,客户端也必须确认。两次握手只能让服务器确认客户端的序号,客户端却无法确认服务器收到了自己的确认——序号 y 从此处于无人担保的状态。

第二,防止历史上旧的重复连接请求造成混乱。 这是 RFC 793 给出的首要原因。设想一条旧的连接报文在网络里迟滞了很久才到达:如果两次握手就建立连接,服务器收到这个陈旧的 SYN 便会单方面进入连接状态,开始等待永远不会来的数据,占住资源。三次握手下,客户端对这个陈旧 SYN 的回应不会带上 ACK,服务器在等待第三次握手时就会发现异常并中止。

三、为什么四次又浪费

理论上服务器可以分两步发 ACK 和 SYN,但这两件事完全可以在同一个报文里捎带完成(SYN+ACK)。协议设计上没有理由为能合并的事多付一个报文的往返时间(RTT)。

四、一个常见的误读

「三次握手是为了确认双方收发能力都正常」是常见的通俗说法,方向不错但不够精确。RFC 的原始动机是序号同步与旧重复报文的防御——收发能力验证只是序号同步的副产品。

参考与核查

  • RFC 9293(2022 年,综合并取代 RFC 793),§3.5「Establishing a Connection」,公开可查:https://www.rfc-editor.org/rfc/rfc9293
  • RFC 793 §3.4「Why Three Segments?」原文阐述了旧重复连接请求的问题
  • SYN 消耗序号、FIN 消耗序号的事实均可在上述 RFC 中核对

评论