TCP 协议如何保证性能( 二 )


客户端向服务端发送数据包(FIN = 1,seq = x)随后进入 FIN-WAIT-1 状态,即半关闭阶段 。
服务端收到客户端的数据包后,发送确认释放连接数据包(ACK = 1,seq = y,ack = x + 1),发送完毕后进入 CLOSE-WAIT 状态 。
客户端收到服务端返回的报文后,确认服务端已经确定它的连接释放请求,并进入 FIN-WAIT-2 状态 。
服务端发送确定释放连接后,再次发送新的报文(FIN = 1,seq = w,ack = x + 1),发送完毕后进入 LAST-ACK 状态 。
客户端收到服务端发送的数据包后,确定服务端想要释放它到客户端的连接,发送数据包(ACK = 1,seq = x + 1,ack = w + 1)并进入 TIME-WAIT 状态 。
服务端收到客户端的数据包后,确认客户端已经知道自己想要释放连接,进入状态 。
客户端发送完数据包,等待满 2MSL 之后,进入状态,至此四次挥手结束 。
简单来说,经过前两次挥手,服务端已经知道客户端想要释放连接,并且客户端知道服务端已经确定自己想要释放连接了 。后两次挥手主要使客户端知道服务端也想释放连接,并且服务端知道客户端已经确定自己想要释放连接了 。此时客户端服务端都确定互相想要中断连接,因此安全释放连接 。
下面我通过抽象例子解释四次挥手和三次握手的过程:
A 和 B 要分手了:
第一次挥手:A 对 B 说:我们分手吧
第二次挥手:B 回复 A :分手可以,等我把我东西收拾完!
第三次挥手:B 告诉 A:我的东西我都收拾好了,正式分手!
第四次挥手:A 回复 B:那就正式分手吧
过了一个月…
A 非常想念 B:
第一次握手:A 对 B 说:这段时间我一直在想你,我们复合吧
第二次握手:B 回复 A:我也是,正式复合吧
第三次握手:A 对 B 说:明天见~
为什么握手三次就可以,挥手需要四次?
对于握手来说,重点在于让双方确定它们之间的连接通畅 。前两次握手使客户端确定连接通畅,其中第二次握手不仅使客户端知道双向连接通畅,并且可以做为服务端确定连接是否通畅的基础,后续只要服务端收到客户端的应答,它就可以确定自己到客户端以及客户端到自己的连接通畅 。
但对于挥手来说,它的核心在于挥手不是同时进行的:也就是说,客户端想要断开连接时,服务端不一定想要断开,只能通过分别断开的方式分步进行 。前两次挥手客户端确定自己想要断开连接并得到服务端确定,但此时服务端不一定想要断开连接,因为存在数据还未发送完毕的情况,并且此时客户端照相可以处理服务端的请求 。在这种情况下就需要服务端再通过两次挥手告诉客户端自己也想断开连接,只有当双方都确定以及让对象确定要断开连接时,这通连接才正式中断 。
为什么最后客户端等待 2 * MSL 的时间?
这里我认为主要是为了保证服务端收到客户端回复的确认断开报文 。假如客户端回复的确认报文由于网络安全问题丢失,对于服务端来说:我发送了断开连接报文,你没有回复 。可能断开连接报文没有发送过去,就会再发送一次断开连接报文,在这 2 * MSL 时间内,如果客户端再次受到该报文,就可以重新发送新的断开连接报文,确定连接正常断开 。
其次,等待期间也可以处理掉之前由于网络问题滞留的数据包,对于滞留在通道中的数据包,等待期间到达服务器时,服务器已确认断开,这部分滞留的数据包就不会产生影响 。假如不等待这 2 * MSL 时间,客户端和服务端重新握手后,这部分报文段就会影响到新的连接 。
TCP 协议如何保证可靠性
前面我们简单介绍了 TCP 建立连接以及断开连接的过程,下面我们主要来看看在具体数据传输过程中,TCP 如何保证可靠性 。