TCP 建立连接需要客户端与服务器交换三个报文,这就是常说的「三次握手」。本文只回答一个问题:为什么恰好是三次,两次不行吗?
一、三次握手做了什么
设客户端的初始序号为 x,服务器的初始序号为 y:
客户端 → 服务器 SYN, seq = x
服务器 → 客户端 SYN+ACK, seq = y, ack = x + 1
客户端 → 服务器 ACK, ack = y + 1
两个关键点:
- SYN 报文消耗一个序号。所以服务器确认的是
x + 1,表示「你发的 SYN 我收到了,下一个字节从 x+1 开始」。 - 第三次握手的 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 中核对
评论