本文试图解释为什么建立TCP连接必须是三次握手,而不是两次或者四次或者不握手。以A向B请求建立TCP连接为例。
前提知识1、网络层实现的传输是不可靠的,TCP是可靠传输
此处的可靠是非常狭义,有具体所指的可靠。链路层在两个网络节点间传递数据时会使用循环冗余检测检查数据是否在传输过程中有错误,如果有就丢弃数据包,网络层乃至传输层的UDP协议并未对此做什么改变。所以这种传输是不可靠的(丢弃之后数据包就消失了,并且不做任何补救措施)。而TCP的可靠之处在于尽量保证数据能传给对方,仅此而已。
2、TCP的可靠传输实现在于两个方面(单个数据包的可靠和多个数据包的可靠)
假设A计算机使用TCP协议给B计算机发数据。首先单个数据包的可靠,TCP要求B计算机收到数据后必须发回一个确认报文,如果A长时间未收到确认,或者收到B的报文说数据错了,A就会重传一次,直到B确认收到。由此可见,可靠传输是靠一去一回实现的。其次多个数据包的可靠,如果一段数据非常长(一般是超过1500字节,由下层物理特性决定),会分成n段一段一段发送。而由于计算机网络采用分组交换,无法保证先发的数据就一定先到,所以需要给每一段标号。起始标号不从0开始,而是随机产生一个数,这是为了区分上一个TCP连接发送的数据和这一个连接的数据,如果每次都从0开始,则如果网络中有残留的上一次连接的数据,会对这次连接造成干扰。
3、TCP连接是全双工的
当TCP连接建立后,A可以给B发数据,B也可以给A发数据,两个过程可以同时进行,互不干扰。
为什么是三次握手为了实现可靠传输和全双工这两个特性,在连接建立前A和B都必须知道一些必要数据,包括A给B发数据的开始序号和A的接收窗口大小,B给A发数据的开始序号和B的接收窗口大小。由单个数据包的可靠传输的原理可知,需要一去一回两次,也就是四次握手:
A-->B 请求建立TCP连接,附加数据:A的开始序号等
B-->A 已收到请求和数据
B-->A 附加数据:B的开始序号等
A-->B 已收到数据
其中第二次的B给A确认和第三次的B给A发送B的开始序号可以合成一个报文。这就是三次握手的由来。
A-->B 请求建立TCP连接,附加数据:A的开始序号等
B-->A 已收到请求和数据,附加数据:B的开始序号等
A-->B 已收到数据
为什么两次握手和四次握手不行三次握手就是四次握手的简化,功能和效果完全一样,还节省一次发数据的时间,所以四次握手没有必要。
如果偷鸡简化为两次握手,省略掉第三次A发给B的确认信号,似乎没有什么不妥。但是违背了可靠传输的原则:收到数据必须反馈一个确认信号。由此导致B无法得知A是否收到B的数据,并且TCP连接不再是全双工连接。假如A发起连接请求后,AB间建立了连接,A不先给B发数据而是等待B先给A发数据。由于二次握手无法保证A知道B的开始序号,所以B是不能贸然发送数据的。
《计算机网络》一书的观点《计算机网络》认为核心在于建立连接的时机不同:三次握手中A在收到第二次握手时建立连接,B在收到第三次握手时建立连接连接。两次握手中A在收到第二次握手时建立连接,B在收到第一次握手时建立连接。
两次握手:如果A给B发送的请求走了远路,超时又发送第二次并完成通信全过程,关闭连接。此后第一个请求到达B,B立即建立连接,但是A已经不在线了,B只能一直等待,浪费资源。如果是三次握手:B在收到迟到的请求后会进行第二次握手确认,多次重传A仍然没有响应,B就会释放资源。
个人认为,这是一方面,不过三次握手也不能从根本上解决这类问题,只是降低了发生的概率,更重要的是两次握手违背了可靠传输和全双工的原则。