为了清楚地掌握在连接建立、连接终止以及数据传送时发生的所有不同事件,TCP以下图所示的有限状态机的形式来定义。
该图将TCP客户和服务器使用的两个FSM合并成了一张图。
圆角框代表的是状态
从一个状态到另一个状态到转换用有向连接表示
每一条连线都注上用斜线隔开的两个字符串
第一个字符串是输入,即TCP接收到了什么
第二个字符串是输出,即TCP发送出去了什么
图中的黑色虚线代表的是通常由服务器经历的转换,而黑色实现代表的是通常由客户经历的转换。
不过某些情况下,服务器的转换可以经过黑色实线,而客户的转换可以经过黑色虚线。
带灰底的线条所示为特殊情况。
请注意,标记为ESTABLISHED的圆角框实际上代表了两组状态,一组是客户的,一组是服务器的,他们用于流量和差错控制。
在状态图中,标记为ESTABLISHED的状态实际上是两组不同的状态,它们是客户和服务器进行数据传送时的状态
状态 | 说明 |
---|---|
CLOSED | 没有连接 |
LISTEN | 收到了被动打开,等待SYN |
SYN- SENT | 已发送SYN;等待ACK |
SYN-RCVD | 已发送SYN+ACK;等待ACK |
ESTABLISHED | 连接建立;数据传送在进行 |
FIN- WAIT-1 | 第一个FIN已发送;等待ACK |
FIN-WAIT-2 | 对第一个FIN的ACK已收到;等待第二个FIN |
CLOSE-WAIT | 收到第一个FIN,已发送ACK;等待应用程序关闭 |
TIME- WAIT | 收到第二个FIN,已发送ACK,等待2MSL超时 |
LAST- ACK | 已发送第二个FIN;等待ACK |
CLOSING | 双方都已决定同时关闭 |
几种情况
连接建立和半关闭终止
我们要描绘 服务器进程发起被动打卡和被动关闭,而客户发起主动打开和主动关闭的情况。
客户状态 客户进程向它的TCP发出一个命令,以请求连接到某个特定的套接字地址,这就称为主动打开。
于是 TCP发送一个SYN报文段,并进入SYN- SENT状态。
在收到SYN+ACK报文段之后,TCP发送ACK报文段,并进入ESTABLISHED状态。
此后数据开始传送和确认,一般都是双向的。当客户进程没有更多的数据要传送时,就发出称为主动关闭的命令。
于是客户TCP发送FIN报文段,并进入FIN-WAIT-1状态。
当它收到对刚才发送的FIN报文段的ACK后,就进入到FIN- WAIT-2状态,并继续留在这个状态,直至收到一个来自服务器的FIN报文段为止。
在收到这个FIN报文段后,客户就发送ACK报文段,并进入TIME-WAIT状态
同时设置一个计时器,它的超时时间是最大报文段寿命(MSL)的两倍。MSL是一个报文段被丢弃之前在因特网中能够生存的最大时间。TCP报文段是封装在生存时间(TTL)受限的IP数据报中。当IP数据报被丢弃时,封装在其中的TCP报文段也就丢失了。MSL的常用数值是30~60秒。
通过时间线来展示同样的过程:
这里有两个理由使得我们需要有TIME- WAIT状态和2MSL计时器。
如果最后一个ACK报文段丢失了,那么服务器TCP(它为最后的FIN设置了计时器)以为是它的FIN丢了,因而重传它。如果客户已进入CLOSED状态,并在2MSL计时器超时之前就关闭了这条连接,那么客户就永远收不到这个重传的FIN报文段,因而服务器也就永远收不到最后的ACK。服务器无法关闭这条连接。2MSL计时器可以使客户等待足够长的时间,使得在ACK丢失(一个MSL)的情况下,可以等待下一个FIN的到来(另一个MSL)。如果在 TIME- WAIT状态中有一个新的FIN到达了,客户就发送一个新的ACK,并重新启动这个2MSL计时器。
某个连接中的重复报文段可能会出现在下一个连接中。假定客户和服务器已经关闭了连接。经过短暂的时间后,它们又打开了一个新的连接,使用的是相同的套接字地址(同样的源地址和目的地址,同样的源端口号和目的端口号)。如果这两个连接之间的时间间隔很短,那么前一个连接中的重复报文段有可能会到达新连接中,同时被解释为属于这个新连接的报文段。为了避免这个问题, TCP规定这种化身必须经过2 MSL时间之后才能出现。但是在某些实现中,如果这个化身的初始序号大于前一个连接使用的最后一个序号,就会忽略这个规则