zoukankan      html  css  js  c++  java
  • TCP的TIME_WAIT状态

     主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),在windows下默认240秒,MSL是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒,因而,TIME_WAIT状态一般维持在1-4分钟。

    TIME_WAIT状态存在的理由:

    1)可靠地实现TCP全双工连接的终止:(即在TIME_WAIT下等待2MSL,只是为了尽最大努力保证四次握手正常关闭)。

          TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。

        在进行关闭连接四路握手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,因此客户端必须维护状态信息允许它重发最终的ACK。如果不维持这个状态信息,那么客户端将响应RST分节,因而,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭的客户端必须维持状态信息进入TIME_WAIT状态。

        我们看客户端主动关闭服务器被动关闭四次握手的流程:

    1、 客户端发送FIN报文段,进入FIN_WAIT_1状态。

    2、 服务器端收到FIN报文段,发送ACK表示确认,进入CLOSE_WAIT状态。

    3、 客户端收到FIN的确认报文段,进入FIN_WAIT_2状态。

    4、 服务器端发送FIN报文端,进入LAST_ACK状态。

    5、 客户端收到FIN报文端,发送FIN的ACK,同时进入TIME_WAIT状态,启动TIME_WAIT定时器,超时时间设为2MSL。

    6、 服务器端收到FIN的ACK,进入CLOSED状态。

    7、 客户端在2MSL时间内没收到对端的任何响应,TIME_WAIT超时,进入CLOSED状态。

          如果不考虑报文延迟、丢失,确认延迟、丢失等情况,TIME_WAIT的确没有存在的必要。当网络在不理想的情况下通常会有报文的丢失延迟发生,让我们看下面的一个特例:

         客户端进入发送收到四次握手关闭的最后一个ACK后,进入TIME_WAIT同时发送ACK,如果其不停留2MSL时间,而是马上关闭连接,销毁连接上的资源,当发送如下情况时,将不能正常的完成四次握手关闭:

    客户端发送的ACK在网路上丢失,这样服务器端收不到最后的ACK,重传定时器超时,将重传FIN到客户端,由于客户端关于该连接的所有资源都释放,收到重传的FIN后,它没有关于这个FIN的任何信息,所以向服务器端发送一个RST报文端,服务器端收到RST后,认为搞连接出现了异常(而非正常关闭)。

    所以,在TIME_WAIT状态下等待2MSL时间端,是为了能够正确处理第一个ACK(最长生存时间为MSL)丢失的情况下,能够收到对端重传的FIN(最长生存时间为MSL),然后重传ACK。

         是否只要主动关闭方在TIME_WAIT状态下停留2MSL,四次握手关闭就一定正常完成呢?

         答案是否定的?可以考虑如下的情况, 

         TIME_WAIT状态下发送的ACK丢失,LAST_ACK时刻设定的重传定时器超时,发送重传的FIN,很不幸,这个FIN也丢失,主动关闭方在TIME_WAIT状态等待2MSL没收到任何报文段,进入CLOSED状态,当此时被动关闭方并没有收到最后的ACK。所以即使要主动关闭方在TIME_WAIT状态下停留2MSL,也不一定表示四次握手关闭就一定正常完成。


    2)确保老的报文段在网络中消失,不会影响新建立的连接 

            考虑如下的情况,主动关闭方在TIME_WAIT状态下发送的ACK由于网络延迟的原因没有按时到底(但并没有超过MSL的时间),导致被动关闭方重传FIN,在FIN重传后,延迟的ACK到达,被动关闭方进入CLOSED状态,如果主动关闭方在TIME_WAIT状态下发送ACK后马上进入CLOSED状态(也就是没有等待)2MSL时间,则上述的连接已不存在:

           现在考虑下面的情况,假设客户端(192.186.0.1:23) 到服务器192.168.1.1:6380)的TCP连接, 由于连接已关闭,我们可以马上建立一个相同的IP地址和端口之间的TCP连接,并且这个连接也是客户端(192.186.0.1:23) 到服务器192.168.1.1:6380),那么当上一个连接的重传FIN到达主动关闭方时,被新的连接所接受,这将导致新的连接被复位,很显然,这不是我们希望看到的事情。

           新的连接要建立,必须是在主动关闭方和被动关闭方都进入到CLOSED状态之后才有可能。所以,最有可能导致旧的报文段影响新的连接的情况是:

          在TIME_WAIT状态之前,主动关闭方发送的报文端在网络中延迟,但是TIME_WAIT设定为2MSL时,这些报文端必然会在网络中消失(最大生存时间为MSL)。被动关闭方最有可能影响新连接的报文段就是我们上面讨论的情况,对方ACK延迟到达,在此之前重传的FIN,这个报文端发送之后,TIME_WAIT的定时器超时时间肯定大于MSL,在1MSL时间内,这个FIN要么在网络中因为生成时间到达而消失,要么到达主动关闭方被这确的处理,不会影响新建立的连接。

        新的SCTP协议通过在消息头部添加验证标志避免了TIME_WAIT状态。

     

     

    3)有关内核级别的keepalive和time_wait的优化调整

    有关内核级别的keepalive和time_wait的优化调整 vi /etc/sysctl net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_keepalive_time = 1800 net.ipv4.tcp_fin_timeout = 30 net.core.netdev_max_backlog =8096
    修改完记的使用sysctl -p 让它生效 以上参数的注解 /proc/sys/net/ipv4/tcp_tw_reuse 该文件表示是否允许重新应用处于TIME-WAIT状态的socket用于新的TCP连接。
    /proc/sys/net/ipv4/tcp_tw_recycle recyse是加速TIME-WAIT sockets回收
    对tcp_tw_reuse和tcp_tw_recycle的修改,可能会出现.warning, got duplicate tcp line warning, got BOGUS tcp line.上面这二个参数指的是存在这两个完全一样的TCP连接,这会发生在一个连接被迅速的断开并且重新连接的情况,而且使用的端口和地址相同。但基本 上这样的事情不会发生,无论如何,使能上述设置会增加重现机会。这个提示不会有人和危害,而且也不会降低系统性能,目前正在进行工作
    /proc/sys/net/ipv4/tcp_keepalive_time 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时
    /proc/sys/net/ipv4/tcp_fin_timeout 最佳值和BSD一样为30 fin_wait1状态是在发起端主动要求关闭tcp连接,并且主动发送fin以后,等待接收端回复ack时候的状态。对于本端断开的socket连接,TCP保持在FIN-WAIT-2状态的时间。对方可能会断开连接或一直不结束连接或不可预料的进程死亡。
    /proc/sys/net/core/netdev_max_backlog 该文件指定了,在接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目

    4)time_wait的优化处理

    Linux系统中TCP是面向连接的,在实际应用中通常都需要检测连接是否还可用.如果不可用,可分为:
    a. 连接的对端正常关闭.
    b. 连接的对端非正常关闭,这包括对端设备掉电,程序崩溃,网络被中断等.这种情况是不能也无法通知对端的,所以连接会一直存在,浪费国家的资源.
    TCP协议栈有个keepalive的属性,可以主动探测socket是否可用,不过这个属性的默认值很大.
    全局设置可更改/etc/sysctl.conf,加上:
    net.ipv4.tcp_keepalive_intvl = 20 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.tcp_keepalive_time = 60
    在程序中设置如下:
    int keepAlive = 1; // 开启keepalive属性 int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测 int keepInterval = 5; // 探测时发包的时间间隔为5 秒 int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

    setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive)); setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle)); setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));

    setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

  • 相关阅读:
    如何判断某个设备文件是否存在
    shell中export理解误区
    linux命令之tail
    国内较快的gnu镜像:北京交通大学镜像
    Cmake的交叉编译
    linux 命令之grep
    makefile之变量赋值
    makefile之VPATH和vpath的使用
    arm汇编进入C函数分析,C函数压栈,出栈,传参,返回值
    Jlink 软件断点和硬件断点
  • 原文地址:https://www.cnblogs.com/kabi/p/7489198.html
Copyright © 2011-2022 走看看