TCP断开连接中与TIME_WAIT

 上一篇文章中我们讲到了TCP连接的建立过程中的三次握手的起因,这里我们来看看常常出现的TIME_WAIT问题,通过TCP状态转移图我们很容易的可以看出TCP的断开连接是从一个FIN包开始,这个过程经历了FIN-ACK-FIN-ACK的四次交互,这个过程也叫做TCP连接的四次挥手断开连接。如:

                               TCP断开连接中与TIME_WAIT_第1张图片  

①  主动关闭的一方首先发送 序列号为M的FIN包,这个包也是告诉对方没有数据可以发送了,要执行关闭操作。

② 被动关闭的一方在收到FIN包后,以M+1的ACK包确认收到对方的FIN关闭连接包,与此同时被动关闭的一方要看自己是否还有未完成的数据需要进行发送:

       1) 被动方如果此时也无数据需要发送,或者说数据也已经发送完毕 ,将随后发送自己序列号为N的FIN包,告诉主动断开的一方断开连接。

               2 ) 被动方如果此时还有未完成发送的数据,就等待缓冲区的数据全部发送完成。待无可发送数据后在将序列号为N的FIN包发出,告知对方断开连接。

       ③ 当主动断开的一方,再次收到对方发来的FIN包后,立刻回复对该包的确认ACK(N+1),此时主动断开的一方便进入TIME_WAIT状态。

       ④ 此时被动断开的一方正在等待自己FIN的确认,如果随后收到了ACK包,被动断开的一方便进入CLOSED状态。否则将在超时之后重新发送FIN包,直到收到ACK或者超               时次 数耗尽强制放弃连接。

       ⑤ 主动关闭的一方在进入TIME_WAIT以后,需要等待2MSL后无需重发,将进入CLOSED状态。


关于TIME_WAIT状态:

       TCP断开连接中主动发起关闭的一方在发送完最后一个ack后进入TIME_WAIT状态,而被动关闭的一方在LAST_ACK状态等待最后一个ack的到来从而进入CLOSED状态。TIME_WAIT状态有两个存在的理由:

               (1)可靠的实现TCP全双工链接的终止。 这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。 

            (2)允许并等待老的重复的分节在网络中消逝 。我们关闭这个连接,过一段时间后在相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连接已经终止后再现,从而被误解成属于同一链接的某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活msl时间即被丢弃,另一个方向上的应答最多存活msl时间也被丢弃。通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。


所以综上所述,TIME_WAIT状态的存在主要有两个作用:

            1>确保主动发起关闭的一方响应的最后一个ack包能够正常送达。

            2>正常处理网络上可能滞留的老的重复分组数据包等参与的数据。


       值得一提的是,在TCP连接过程中虽然不常见,但是小概率的出现TCP连接的双方同时进入TIME_WAIT的情况。因为常规的情况下都是TCP主动关闭的一方进入TIME_WAIT状态。所以很容易想到双方都进入TIME_WAIT的情形发生在TCP双方同时关闭的情形。如下所示:

                                  TCP断开连接中与TIME_WAIT_第2张图片


           这种情况下连接双方均为主动关闭的一方,两边同时发出了属于自己序列号的FIN包确认后,均受到对方的FIN包,然后发送了对该包的ACK之后,双方均进入TIME_WAIT状态,知道等到2MSL过后才真正意义上实现了TCP的全双工关闭,进入CLOSED状态。


你可能感兴趣的:(TCP/IP)