背景介绍

在《UNIX网络编程》经典书籍中,对TCP连接建立和断开描述了11种TCP状态,书里面有一张经典图片。

TCP的11种状态转移图.png

头一次看(或者过一段时间看)上面这张图,脑袋都会变大,我写这篇文章,就想记录下如何理解这张完整的状态转移图。作用有两个:
一、深入理解TCP的状态转移;
二、针对实际工作种会出现的大量TCP状态(比如TIME_WAIT、CLOSE_WATI),有针对性解决问题的思路。

整体理解

首先,这张图画的是TCP所有的11种状态,以及他们之间转移的条件,可以这样理解,图描述的是一个整体全貌,是所有状态拼在一起的内容,这也就是为啥,我们看着觉得特别复杂。简单来说,我认为在单一的一次TCP传输数据(建立连接->传输数据->断开连接),不会出现所有的11种状态。我总结下来,某一次的TCP连接会有如下几种情况:
一、客户端建立连接,客户端和服务端传输数据,客户端关闭连接;
二、客户端建立连接,客户端和服务端传输数据,服务端关闭连接;
三、客户端建立连接,客户端和服务端传输数据,客户端和服务端同时关闭连接;
也很容易理解,建立连接,只能是客户端主动,只有关闭连接,我们才需要分类讨论。

客户端关闭连接

这个应该是最常规的流程了,从整体图中分离得到的状态转移图如下:

TCP客户端断开连接示意图.png

如果转化位流程图,如下:
TCP客户端断开连接流程图.png

上面这两张图,应该是比较清晰,也不用太多的解释了吧?有时间补充实际操作的代码,结合代码能够看到状态转移,我想理解会更加深刻的。

服务端关闭连接

和上面客户端关闭连接一样,我也整理两张容易理解的图,
服务端关闭连接示意图.png
服务端关闭连接流程图.png

客户端和服务端同时关闭连接

这个情况就相对复杂些,分2种情况讨论下。第一种情况两端同时关闭连接,也同时收到对方发送的FIN包,如下图:

两边同时关闭同时收到FIN包.png

第二种情况两端同时关闭连接,但其中一方先收到FIN包(以客户端先收到FIN包为例,反之亦然),如下图:

双方同时关闭连接一方先收到FIN包.png

异常状态的讨论

实际工作中,会经常遇到服务器出现大量TIME_WAIT或者CLOSE_WATI的状态。
TIME_WAIT根据上面的分析,主动关闭连接方在ACK对端FIN包后处于的状态,也被称为2MSL等待状态。每个具体 TCP 实现必须选择一个报文段最大生存时间 MSL(Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。所以TIME_WAIT状态保证了两点:1. 可靠地实现 TCP 全双工连接的终止;2. 允许老的重复分节在网络中消逝。如果服务器上出现大量的TIME_WAIT状态,很可能是有大量的短连接,此时有可能的措施有这么几个,减少MSL的时长、短连接变为长连接。
CLOSE_WAIT状态时被动关闭连接的一方会处于的状态,只要收到了对端的FIN包,回复了对应的ACK包,就变成了CLOSE_WAIT状态,但是如果此时我们服务程序(异常原因)没有继续调用close()函数,导致未发送FIN包,就会造成这个连接一直处于CLOSE_WAIT状态,此时需要排查程序,弄清楚在什么异常场景下,导致程序未发送FIN包。

参考资料:
https://zhuanlan.zhihu.com/p/78540103
https://www.jianshu.com/p/eb0d3e4744f1
https://blog.csdn.net/yu616568/article/details/44677985

标签: none

已有 2 条评论

  1. 1 1

    1

  2. 1 1

    555

添加新评论