我们都知道 tcp 协议需要三次握手,那为什么不是两次握手呢,关于这个疑问我查了很多资料,看到很多的解释,现归纳总结如下,方便我们理解记忆
如果是两次握手,我们一起来看看下面两种场景
1. 造成资源浪费
- Client 向 Server 发送了一个 a1 的包
假如这时由于传输链路上遇到故障,导致 a1 传输到 Server 的时间特别长 假设 1min
在这一分钟的时间内,由于 Client 没有收到 Server 对于 a1 包的确认,Client 会以为上一个包发送丢了或者失败
那么 Client 会再发送一个 a2 的包
- Client 又向 Server 发送了一个 a2 的包
这次 Server 正常收到
- 于是 Server 向 Client 发送了一个 b2 的确认包
- Client 和 Server 建立链接
而随后滞后的 a1 包传到了 Server,Server 又会返回 b1 包确认
但是由于 Client 已经清除了 a1 包,所以 Client 会丢弃掉这个包,但是 Server 又会保持这个相当于“僵尸”的连接
这样就会造成白白浪费资源
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段又突然传送到服务器,因为产生错误”
在另一部经典的《计算机网络》(AndrewS.Tanenbaum 著,第四版)一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。
我们会发现这两种不同的表述其实阐明的是同一个问题。
2. 死锁可能发生
- Client 向 Server 发送了一个连接请求分组
- Server 收到这个分组,并发送了确认应答分组
按照两次握手的协定,Server 认为已经成功的建立连接,可以开始发送数据分组
而此时 Server 的应答分组传输丢失了,Client 不知道 Server 是否已准备好,不知道 Server 建立什么样的序列号
Client 甚至怀疑 Server 是否收到了自己的连接请求分组,在这种情况下,Client 认为连接还未建立成功,将忽略 Server 发来的任何数据请求,只等待连接确认影带分组。而 Server 在发出的分组超时后,重复发送同样的分组,资源就形成了死锁。
而上面两种情况,如果使用三次握手就可以成功避免,三次握手完成的两个重要功能
- 既要双方做好发送数据的准备工作(双方都知道彼此已准备好)
- 允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认