TCP状态转换

TCP状态转换图

       TCP连接的建立与终止,以及在连接的不同阶段需要发送的各种类型的报文段,实质上都是由TCP所属的状态决定的。当前的状态会在各种触发条件下改变,状态转换规则可以概括为如下所示的TCP状态转换图:

TCP状态转换

       TCP初始化时从CLOSED状态启动,通常根据是执行主动打开操作(客户端请求)还是被动打开操作(服务器接收请求),TCP将分别转换到SYN_SENT或LISTEN状态。正常情况下处于这两个状态下的两者由此建立了连接,这就是三次握手过程

       左下方的FIN_WAIT_1、FIN_WAIT_2以及TIME_WAIT是“主动关闭”过程的状态转换,而CLOWSE_WAIT和LAST_ACK则是“被动关闭”过程涉及的状态转换。

       从LISTEN到SYN_SENT的状态转换只有在WYN_RCVD状态是由LISTEN状态而非WYN_SENT状态转换而来的情况下才会发生。这意味着,如果我们执行一个被动打开操作(进入LISTEN状态),接收一个SYN,发送一个带有ACK确认的SYN(进入SYN_RCVD状态),然后收到一个重置消息而非ACK,套接字就会返回到LISTEN状态,等待另一个连接请求的到来。

       结合TCP连接从建立到终止的过程,可以得到下图:

TCP状态转换

       图中由小写字母组成的词来源于POSIX标准的网络编程相关函数

FIN_WAIT2

       在FIN_WAIT2状态,TCP连接的主动关闭方已发送一个FIN报文段并得到另一端确认。除非出现半关闭的情况,否则主动关闭方将会等待另一端识别出自己已接收到一个文件末尾的通知并执行关闭连接操作。只有主动关闭方接收到另一端的FIN报文段,才会从FIN_WAIT2状态转移至TIME_WAIT状态。

TIME_WAIT

       TIME_WAIT状态也称为2MSL等待状态。在该状态中,TCP套接字将会等待两倍于最大段生存期(Maximum Segment Lifetime,MSL)的时间。它代表任何报文段在被丢弃前在网络中允许存在的最长时间。虽然允许设置这个数值,但同时也受到网络层中IP数据报TTL字段的影响,因为TCP报文是以IP数据报的形式传输的。

       当TCP连接主动关闭方接收到被动关闭方发送的FIN和最终的ACK后,连接的主动关闭方必须处于TIME_WAIT状态并持续2MSL时间。这样就能够让TCP连接的主动关闭方在它发送的ACK丢失的情况下重新发送最终的ACK。主动关闭方重新发送的最终ACK并不是因为被动关闭方重传了ACK(它们并不消耗***,被动关闭方也不会重传),而是因为被动关闭方重传了它的FIN。事实上,被动关闭方总是重传FIN直到它收到一个最终的ACK。

       假设没有TIME_WAIT状态,如果被动关闭方没有收到主动关闭方回复的ACK,它就会重新发送FIN,但此时主动关闭方已经处于CLOSED状态,因此会响应一个RST报文段,让被动关闭方误认为发生了错误。因此TIME_WAIT状态存在的其中一个原因就是为实现TCP连接的可靠释放。

       使用TIME_WAIT状态的另一个原因是为使旧的数据包在网络因过期而消失。假设TCP协议中不存在TIME_WAIT状态的限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port)。因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。由于一个连接仅由两对socket唯一标识,因此TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立的过程对其来说是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。

       出于第2个原因的考虑,TCP协议规定在TIME_WAIT状态时,通信双方将连接(客户端IP地址、客户端端口号、服务器IP地址、服务器端口号)置于不可用状态。只有当2MSL等待结束时,或一条新连接使用的初始***超过了连接之前的实例所使用的最高***时[RFC1122],或者允许使用时间戳选项来区分之前连接实例的报文段以避免混淆时[RFC6191],这条连接才能重新使用。

 

                                                                      本文部分内容摘自《TCP/IP详解 卷1:协议(中文版)第2版》,有改动