5月31日 00:26

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

TCP 三次握手的重点不是“发了三次包”,而是让双方确认三件事:对方能收、对方能发、双方的初始序列号都同步了。客户端先发 SYN,带上自己的 seq=x;服务端回 SYN+ACK,确认 x 并给出 seq=y;客户端再回 ACK,确认 y。到这一步,双方才有足够信息进入 ESTABLISHED,后续字节流才能可靠编号和确认。

三次握手的过程怎么走?

文字时序图可以这样看:客户端说“我要连,seq=x”;服务端说“收到 x,我这边 seq=y”;客户端再说“收到 y”。第一次后客户端进入 SYN_SENT,第二次后服务端进入 SYN_RCVD,第三次到达后双方进入 ESTABLISHED。ack=x+1、ack=y+1 不是随便加 1,而是 SYN 本身会占用一个序列号。

为什么两次握手不够?

两次握手的问题是服务端无法确认客户端是否收到了自己的 SYN+ACK。假设网络里一个过期 SYN 延迟到达服务端,如果两次就建立连接,服务端可能误分配资源,而客户端根本没有这次连接意图。第三次 ACK 能让服务端确认“客户端确实收到了我的序列号”。取舍是多半个往返,但换来更明确的状态确认。

为什么不是四次握手?

四次也能完成目标,只是没必要。服务端本可以先 ACK 客户端序列号,再单独发 SYN;TCP 把这两步合并成 SYN+ACK,少发一个报文。三次已经完成双方序列号同步和收发能力确认,再拆成四次只会增加成本。

第三次 ACK 丢了会怎样?

客户端通常已经认为连接建立,可以继续发送数据。服务端还停在 SYN_RCVD,等待 ACK 或重传 SYN+ACK;如果客户端后续数据包带 ACK,服务端也可能借此完成建连。边界是客户端不再发任何数据,服务端会超时重传,最后释放半连接资源。

三次握手和 SYN Flood 有什么关系?

服务端收到 SYN 后需要保存半连接状态,SYN Flood 就利用了这点。攻击者大量发 SYN 却不完成第三次 ACK,半连接队列可能被占满。防御常见做法包括 SYN Cookies、调大半连接队列、缩短重试、限流和流量清洗;取舍是队列调大会耗内存,SYN Cookies 也可能影响部分 TCP 选项能力。

追问

三次握手能证明应用层一定可用吗?

不能,它只能证明传输层基本收发链路是通的。握手成功后,TLS、鉴权、线程池、数据库都可能继续失败。排查时要分清边界,“端口通”不等于“接口健康”,很多慢请求卡在握手之后。

初始序列号为什么要随机?

随机初始序列号能降低旧报文混入新连接的概率,也增加伪造 TCP 报文的难度。早期序列号可预测时,攻击者更容易猜中合法窗口。代价是双方必须在握手阶段交换序列号,抓包工具显示相对序列号只是为了方便阅读。

服务端收到 SYN 后马上分配资源,会不会有风险?

有风险,所以内核会限制半连接队列并设置超时重传。SYN Flood 正是利用这个窗口消耗资源。工程上不能只调 backlog,还要看 somaxconn、tcp_max_syn_backlog、SYN Cookies 和应用 accept 速度。

握手协商的参数会影响后续传输吗?

会,MSS、窗口扩大、SACK、时间戳通常都在握手阶段协商。窗口扩大失败可能让高 RTT 链路吞吐上不去,SACK 不可用会降低多包丢失后的恢复效率。排查慢连接时,不能只看握手成功,还要看握手里协商出了什么能力。

标签:TCP