【TCP】状态转换

TCP状态转换

    

     这个图N多人都知道,它排除和定位网络或系统故障时大有帮助,但是怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻的认

识,不能只停留在一知半解之中。下面对这张图的11种状态详细解析一下,以便加强记忆!不过在这之前,先回顾一下TCP建立连接的三次握手过程,以及关闭连接的四次握手

过程。

                                                  

                                                                                      tcp 状态转换图

 

         CLOSED:      表示初始状态。

         LISTEN :       表示服务端的某个 SOCKET 处于监听状态,可以接受连接。

         SYN_SENT:  与 SYN_RCVD 遥相呼应,当客户端的  SOCKET  执行 CONNECT 连接时它首先发送 SYN报文,随即进入到了 SYN_SENT 状态,并等待服务端的发送

三次握手中的第二个报文。SYN_SENT 状态表示客户端已经发送SYN报文。

        SYN_RCVD:  该状态表示接收到 SYN 报文,在正常情况下,这个状态是服务器的 SOCKET 建立TCP 连接时的三次握手中会话过程中的一个中间装态,很短暂。此种状

态时,当收到客户端的 ACK 报文后,会进入到 ESTABLISHED 状态。

        ESTABLISHED: 表示连接已经建立 。

        FIN_WAIT_1:FIN__WAIT_1 和 FIN_WAIT_2 状态的真正含义都是表示等带对方的 FIN 报文。区别是:

                                FIN_WAIT_1  状态是当 socket 在 ESTABLISHED 状态时,想主动关闭连接,向对方发送了 FIN 报文,此时该 socket 进 入到 FIN_WAIT_1 状态。

                                FIN_WAIT_2  状态是当对方回应 ACK 后,该 socket 进入  FIN_WAIT_2 状态,正常情况下,对方应马上回应  ACK 报文,所以 FIN_WAIT_1 状态一般很难

见到,而 FIN_WAIT_2 可用netstat 查看。

         FIN_WAIT_2:主动关闭连接的一方,发出 FIN 收到 ACK以后进入到该状态称为半连接状态或半关闭状态。改状态下的 socket 只能接收数据,不能发送数据。

         TIME_WAIT: 表示收到了对方的 FIN 报文,并发送出了 ACK 报文,等 2 MSL 后即可回到 CLOSED 状态。如果 FIN_WAIT_1 状态下,收到对方同时带 FIN 和 ACK 的标

志报文时,可以直接进入到 TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。

         CLOSING:  这种状态比较特殊,属于一种罕见的状态。正常情况下,当你发送 FIN 报文后,按理来说是应该先收到(或同时收到)对方的 ACK 报文,在收到对方的 

FIN报文。但是 CLOSING 状态表示的是你发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却收到了对方的 FIN 报文。什么情况下会出现此种情况呢?如果双方几乎在同

时 close 一个 socket 的话,那么就出现了双方同时 FIN 报文的情况,也会出现 CLOSING 状态,表示双方都正在关闭 socket 连接。

         CLOSE_WAIT:  此种状态表示在等待关闭。当对方关闭一个SOCKET后发送FIN报文给自己,系统会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来

呢,察看是否还有数据发送给对方,如果没有可以 close这个SOCKET,发送FIN报文给对方,即关闭连接。所以在CLOSE_WAIT状态下,需要关闭连接。

        LAST_ACK:  该状态是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,即可以进入到CLOSED可用状态。


半关闭

      

      当TCP链接中A发送FIN请求关闭,B端回应ACK后(A端进入FIN_WAIT_2状态),B没有立即发送FIN给A时,A方处在半链接状态,此时A可以接收B发送的数据,但是A已

不能再向B发送数据。从程序的角度,可以使用API来控制实现半连接状态。

   

           	#include <sys/socket.h>

		int shutdown(int sockfd, int how);

			sockfd: 需要关闭的socket的描述符
	
			how:	允许为shutdown操作选择以下几种方式:

				SHUT_RD(0):	关闭sockfd上的读功能,此选项将不允许sockfd进行读操作。
						该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被无声的丢弃掉。
	

				SHUT_WR(1):		关闭sockfd的写功能,此选项将不允许sockfd进行写操作。进程不能在对此套接字发出写操作。


				SHUT_RDWR(2):	关闭sockfd的读写功能。相当于调用shutdown两次:首先是以SHUT_RD,然后以SHUT_WR。
           

          使用close中止一个连接,但它只是减少描述符的引用计数,并不直接关闭连接,只有当描述符的引用计数为0时才关闭连接。

shutdown不考虑描述符的引用计数,直接关闭描述符。也可选择中止一个方向的连接,只中止读或只中止写。


   注意:

             1.        如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。

             2.        在多进程中如果一个进程调用了shutdown(sfd, SHUT_RDWR)后,其它的进程将无法进行通信。但,如果一个进程close(sfd)将不会影响到其它进程。

2MSL

             2MSL (MaximumSegment Lifetime) TIME_WAIT状态的存在有两个理由:

          (1)、让4次握手关闭流程更加可靠;4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会再次发一个FIN过来。若主动关闭方能够保

持一个2MSL的TIME_WAIT状态,则有更大的机会让丢失的ACK被再次发送出去。

           (2)、防止lostduplicate对后续新建正常链接的传输造成破坏。lost uplicate在实际的网络中非常常见,经常是由于路由器产生故障,路径无法收敛,导致一个packet在

路由器A,B,C之间做类似死循环的跳转。IP头部有个TTL,限制了一个包在网络中的最大跳数,因此这个包有两种命运,要么最后TTL变为0,在网络中消失;要么TTL在变为

0之前路由器路径收敛,它凭借剩余的TTL跳数终于到达目的地。但非常可惜的是TCP通过超时重传机制在早些时候发送了一个跟它一模一样的包,并先于它达到了目的地,因

此它的命运也就注定被TCP协议栈抛弃。


另外一个概念叫做incarnationconnection,指跟上次的socket pair一摸一样的新连接,叫做incarnation of previous connection。lost 

uplicate加上incarnationconnection,则会对我们的传输造成致命的错误。


TCP是流式的,所有包到达的顺序是不一致的,依靠序列号由TCP协议栈做顺序的拼接;假设一个incarnation connection这时收到的seq=1000, 来了一个lostduplicate

为seq=1000,len=1000, 则TCP认为这个lost duplicate合法,并存放入了receive buffer,导致传输出现错误。通过一个2MSL TIME_WAIT状态,确保所有的lost duplicate都会消

失掉,避免对新连接造成错误。


         该状态为什么设计在主动关闭这一方

(1)发最后ACK的是主动关闭一方。

(2)只要有一方保持TIME_WAIT状态,就能起到避免incarnationconnection在2MSL内的重新建立,不需要两方都有。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值