TCP连接的建立和关闭状态转移图

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YL970302/article/details/83109668

TCP连接的任意一端在任一时刻都处于某种状态,当前的状态可以通过netstat命令查看,这里我们要讨论的是TCP连接从建立到关闭整个过程中通信两端状态的变化

                                                 

图中粗虚线表示典型的服务器端连接的状态转移;粗实线表示典型的客户端连接的状态转移。请注意,CLOSED是一个假想的起始点,并不是一个实际的状态。

1、讨论服务器端的状态:

  服务器通过listen系统调用进入LISTEN状态,被动的等待客户端连接,因此执行的是所谓的被动打开。服务器一旦监听到某个连接请求(收到同步报文段),就将该连接放入内核等待队列中,并向客户端发送SYN标志的确认报文段。此时该连接处于SYN_RCVD状态。如果服务器成功的接收到客户端发送回的确认报文段,则该连接将转移到ESTABLISHED(已完成三次握手状态)状态。该状态时连接双方能够进行双向数据传输的状态。

  当客户端主动关闭连接时(通过close或shutdown系统调用向服务器发送结束报文段),服务器通过返回确认报文使连接进入CLOSE_WAIT状态(等待服务器应用程序关闭连接)。通常,服务器检测到客户端关闭连接后,也会立即给客户端发送一个结束报文段来关闭连接,这将使连接进入LAST_ACK状态,以等待客户端对结束报文段的最后一次确认,一旦完成,连接就彻底关闭。

2、讨论客户端的连接状态:

  客户端通过connect系统调用主动与服务器建立连接。connect系统调用首先给服务器发送一个同步报文段,使连接转移到SYN_SENT状态。此后,connect系统调用可能因为下面的两个原因失败返回:

(1)如果connect连接的目标端口不存在(未被任何进程监听),或者该端口仍被处于TIME_WAIT状态的连接所占用,则服务器将给客户端发送一个复位报文段,connect调用失败。

(2)如果目标端口存在,但connect在超时时间内未收到服务器确认报文段,则connect调用失败。

  当客户端执行主动关闭时,它将向服务器发送一个结束报文段,同时连接进入FIN_WAIT_1状态。此时客户端接收到服务器专门用于确认目的的确认报文段,则连接转移至FIN_WAIT_2状态。当客户端处于FIN_WAIT_2状态时。服务器处于CLOSE_WAIT状态,这一对状态是可能发生半关闭的状态。此时如果服务器也关闭连接(发送结束报文段),则客户端将给予确认并进入TIME_WAIT状态。

下图是TCP连接进入ESTABLISHED(已完成三次握手)状态:

                                    

下面的图片能更有利于大家对TCP连接时状态转移的理解

                                                 

   1)报文段1、报文段2、报文段3是我们TCP建立连接时的三次握手,那么就会有人问,非得三次握手才行吗?两次不行吗?答案是:不行,因为我们客户端发送报文段1时是向服务器请求连接的,说服务器我要连接你,那服务器就给客户端回复确认报文段2,说好的,然后服务器此时就会等待,等待这个客户端来连接,如果客户端不发送这个对服务器的确认报文段3,那么服务器就会一直等着,但此时,服务器和客户端是连接不上的。所以客户端必须要回复确认报文段3给服务器才能连接上。举个例子:你同学叫你吃饭,你说好,然后你就在食堂等你同学,可是它一直也没有来一样。

  2)从报文段4以后是我们TCP关闭连接的四次挥手操作,那么有人也会问为什么必须是4次呢,三次不可以吗?答案是可以,但是可以三次就能完成关闭连接的前提是,服务器端和客户端恰好同时都想关闭连接,就是说客户端发送结束报文段给服务器想要关闭连接,那此时服务器也想关闭连接,正好呢此时就收到了客户端发的结束报文,那么它就自己的结束报文段和要给客户端发送的确认回复报文就一块发了,最后等待客户端的确认回复报文段7就可以了。(也就是将报文段5和报文段6合在一起发送了)。图3-8中客户端直接从FIN_WAIT1直接到TIME_WAIT状态就是此原因。

3、我们可以用 netstat -natp命令查看哪个端口被占用、套接字的状态、接收缓冲区和发送缓冲区中的数据个数、IP、还有程序名字。如下图所示

                                          

下图是服务器进连接入TIME_WAIT状态

                                      

4、TIME_WAIT存在在的意义:

(1)可靠的终止TCP连接。

  假设上图中用于确认服务器结束报文段6的TCP报文段7丢失,那么服务器重发结束报文段,因此客户端需要停留在某个状态以处理重复收到的结束报文段(即向服务器发送确认报文段)。否则客户端将以复位报文段来回应服务器,服务器则认为这是一个错误,因为它期望的是一个像TCP报文段7那样的确认报文段。

(2)保证让迟来的TCP报文段有足够的时间被识别并丢弃。

    在Linux系统上,一个TCP端口不能被同时打开多次(两次以上)。当一个TCP连接处于TIME_WAIT状态时,我们将无法建立立即使用该连接占用着的端口来建立一个新连接。反过来想,如果不存在TIME_WAIT状态,则应用程序能够立即建立一个和刚关闭的连接相似的连接(这里的相似是指它们具有相同的IP地址和端口号)。这个新的、和原来i相似的链接被称之为原来的连接的化身。新的化身可能接收到属于原来的连接的、携带应用程序数据的TCP报文段(迟到的报文段)这就会造成混乱,这显然是不应该发生的。

5、为什么TIME_WAIT状态要持续3MSL时间?

   因为TCP报文段的最大生存时间是MSL,所以坚持2MSL时间的TIME_WAIT状态能够确保网络上两个传输方向上尚未被接收到的、迟到的TCP报文段都已经消失(被中转路由丢弃)。因此,一个连接的新的化身可以在2MSL时间之后安全地建立,而绝对不会收到属于原来连接的应用程序数据,这就是TIME_WAIT状态要持续2MSL时间的原因。

6、为什么客户端主动执行close关闭连接之后,立即重启客户端程序还能连接成功?

对于客户端程序来说,我们通常不用担心上述的重启问题。因为客户端一般使用系统自动分配的临时端口来建立连接,而由于随机性,临时端口号一般和程序上一次使用的端口号(还处于TIME_WAIT状态的那个连接使用的端口号)不同,所以客户端程序一般可以立即重启。

7、为什么服务器主动执行close关闭连接之后,再立即启动服务器程序却不成功呢?

  对于服务器主动关闭连接后属于异常终止,因为它总是使用同一个知名服务器端口号,所以连接的TIME_WAIT状态将导致它不能立即重启。不过我们可以通过socket选项SOREUSEADDR来强制进程立即使用处于TIME_WAIT状态的连接占用的端口。

8、用tcpdump命令实现抓包,下图是正常的三次握手和四次挥手

                                                 

下图是将四次挥手演化成三次的情况

                                                

猜你喜欢

转载自blog.csdn.net/YL970302/article/details/83109668
今日推荐