TCP建立连接为什么不是两次握手,而是三次,为什么不能在第二次握手时就建立连接?
一.无法确认客户端的接收能力
三次握手的核心目的是为了确认客户端和服务端双方的发送和接收能力: 确保双方都能成功发送和接收数据。
如果C端发送数据到S端,S端收到数据,则可以确认S端具备正常的接收能力;如果C端发送出去的请求被S端响应,则C端可以确认自己具备正常的发送能力和接收能力;如果S端接收到C端的响应,则可以确认自己也具备正常的发送能力。
第一次握手(C->S)可以确认服务端可以正常接收(因为服务端收到了客户端的请求);
第二次握手(S->C)可以确认客户端可以正常发送和接收(因为客户端收到了服务端的响应);
第三次握手(C->S)可以确认服务端可以正常发送(因为服务端的发送的响应被响应了)。
通过三次握手从而最终确认了客户端和服务端双方具备的正常发送和接收能力。
如果在第二次握手时就确认连接,那么就无法确认服务器是否具备正常的接收能力了。
二.防止和服务端资源的浪费(维护无效连接)(比较重要的原因)
设想一个场景:Client 发送了一个 SYN 请求给 Server,但这个 SYN 请求因为网络延迟而在某个路由器上长时间滞留了。
- 随后,Client 由于长时间未收到响应而超时,重新发送了另一个 SYN 请求,并成功与 Server 建立了连接,完成了数据传输,并关闭了连接。
- 此时,那个之前滞留的旧的 SYN 请求突然抵达了 Server。
- 如果 Server 采用两次握手,它收到这个旧的 SYN 请求后,会发送 SYN-ACK 给 Client,并且立即认为连接已经建立(进入
ESTABLISHED
状态)。 - 但 Client 此时对这个 SYN-ACK 是一无所知且完全不期待的(因为它已经完成了之前的连接,或者正在进行其他操作)。Client 会直接发送 RST 报文给 Server,或者忽略这个 SYN-ACK。
- 结果: Server 单方面地认为连接已经建立,但实际上 Client 并没有,导致 Server 浪费资源(维护一个无效的连接状态),甚至可能在 Server 尝试发送数据时,Client 收到数据会直接回复 RST,中断通信。
总结
三次握手最关键的作用是防止旧的、重复的连接请求报文段在网络中游荡,并被服务器误认为是新的连接请求,从而导致服务器建立一个根本不存在的连接。
同时,它也确保了在开始数据传输之前,双方都明确地确认了对方的初始序列号,并确认了对方具备正常的收发数据能力。这是 TCP 可靠性、有序性、流量控制和拥塞控制的基础。