参考
TCP 为什么是三次握手,而不是两次或四次?
1. tcp三次握手流程
image.png
由图可知,tcp三次握手的关键在于,序列号seq的交换确认。
2. 为什么不能是两次握手
因为对于客户端和服务端来说,双方对对方的序列号的确认是可靠传输的关键。 两次握手的过程如下:
- A 发送同步信号SYN A's Initial sequence number
- B 发送同步信号SYN B's Initial sequence number B's ACK sequence number
当第二步的动作完成时,我们可以保证B已知晓A的序列号,因为第二步只有在第一步成功后才执行。但不能保证A知晓B的序列号,因为第二步的传输可能失败。
图中省略了这两次握手中,发送了SYN=1的细节
两次握手完成后,由于我们假设了,tcp只有二次握手,那么二次握手完成时,B就得自认为连接已经建立,不管第二次握手的传输是否成功。 那么,假如第二次握手的传输失败了,A就不会收到B的序列号,也就无法确定B的数据传输起始于第几号。 这时,B向A发送了一些数据(TCP是全双工通信,所以服务端B可以主动向客户端A发信息),并附上了序列号20000,被A收到:
此时A就面临着两个尴尬的选择:
- A可以保持数据包。但是A连B的起始序列号都不知道,这个数据包要保存到什么时候,才能回复ACK呢?
- A可以回复ACK。ACK的含义表示它的序号之前的字节数据都已收到,可是A连B的起始序列号都不知道:起始序列号可能是100,也可以是1000,A根本无法确定还缺哪些序号的字节,也就更不敢回复ACK了。
所以,不管哪个选择,都是不妥当的。这正是因为A没有确认B的序列号。 而在tcp中,通过三次握手,和丢包的处理机制,A和B都会确定自己的序列号被对方接收。
3. tcp对三次握手中丢包的处理
照搬自TCP 为什么是三次握手,而不是两次或四次? tcp除了采用三次握手,还要对丢包意外进行适当的处置,以保证A、B双方序列号的传输和确认。
- 如果第一个包,即A发给B的SYN 中途被丢,没有到达B A会周期性超时重传,直到收到B的确认
- 如果第二个包,即B发给A的SYN ACK 中途被丢,没有到达A B会周期性超时重传,直到收到A的确认
- 如果第三个包,即A发给B的ACK 中途被丢,没有到达B A发完ACK,单方面认为TCP为 Established状态,而B显然认为TCP为Active状态: a. 假定此时双方都没有数据发送,B会周期性超时重传,直到收到A的确认,收到之后B的TCP 连接 也为 Established状态,双向可以发包。 b. 假定此时A有数据发送,B收到A的 Data ACK,自然会切换为established 状态,并接受A的 Data(发ACK的同时顺便把Data带上)。 c. 假定B有数据发送,数据发送不了,会一直周期性超时重传SYN ACK,直到收到A的确认才可以发送数据(没收到A的确认,连接就还没建立,就不能传输数据)。
这样,tcp的三次握手,加上对丢包的处理机制,就保证了A、B对双方序列号的确认。也就建立了可靠传输的基础。
4. 为什么不能是四次握手
把四次握手中的第二和第三步合并起来,就是三次握手了。为了提高效率,是可以合并第2、3步的。