马上又:TCP中time_wait解释及解决方法

首先是四次挥手断开连接的状态变化图


总的来说,主动关闭连接的一方才会进入TIME_WAIT状态。

客户端主动关闭连接时,会发送最后一个ack后,然后会进入TIME_WAIT状态,再停留2个MSL时间,进入CLOSED状态

MSL时间MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间IP数据包将在网络中消失 。MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒。

一个socket连接,可以得出以下几点:

  • 主动关闭连接的一方 – 也就是主动调用socket的close操作的一方,最终会进入TIME_WAIT状态 ;
  • 被动关闭连接的一方,有一个中间状态,即CLOSE_WAIT,因为协议层在等待上层的应用程序,主动调用close操作后才主动关闭这条连接 ;
  • TIME_WAIT会默认等待2MSL时间后,才最终进入CLOSED状态;
  • 在一个连接没有进入CLOSED状态之前,这个连接是不能被重用的
  • time_wait的作用,以及为什么是2*MSL

  • 防止连接关闭时四次挥手中的最后一次ACK丢失

    如果没有TIME_WAIT状态,主动关闭一方(客户端)就会在收到对端(服务器)的FIN并回复ACK后 直接从FIN_WAIT_2 进入 CLOSED状态,并释放连接。此时如果最后一条ACK丢失,那么服务器重传的FIN将无人处理,最后导致服务器长时间的处于 LAST_ACK状态而无法正常关闭(服务器只能等到达到FIN的最大重传次数后关闭) 如果此时新建一个连接,源随机端口如果被复用,在connect发送SYN包后,由于被动方仍认为这条连接【五元组】还在等待ACK,但是却收到了SYN,则被动方会回复RST; 造成主动创建连接的一方,由于收到了RST,则连接无法成功; 将TIME_WAIT的时长设置为 2MSL,是因为报文在链路中的最大生存时间为MSL(Maximum Segment Lifetime),超过这个时长后报文就会被丢弃。TIME_WAIT的时长则是:最后一次ACK传输到服务器的时间 + 服务器重传FIN 的时间,即为 2MSL。
  • 防止新连接收到旧链接的TCP报文:

  • TCP使用四元组区分一个连接(源端口、目的端口、源IP、目的IP),如果新、旧连接的IP与端口号完全一致,则内核协议栈无法区分这两条连接。在关闭“前一个连接”之后,马上又重新建立起一个相同的IP和端口之间的“新连接”,“前一个连接”的迷途重复分组在“前一个连接”终止后到达,而被“新连接”收到了。2*MSL 的时间足以保证两个方向上的数据都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定是新连接上产生的。

    过多的time_wait的坏处
    当连接处于TIME_WAIT状态时仍会占用系统资源(fd、端口、内存),过多的TIME_WAIT状态的连接会对系统的并发量造成影响。

    对客户端的影响:

    当客户端主动关系连接,出现大量的 time_wait时,TIME_WAIT状态的连接就占用了一个本地端口。这样在TIME_WAIT状态结束之前,本地最多就能承受6万个TIME_WAIT状态的连接,就无端口可用了,限制了客户端的并发率,同时,大量的TIME_WAIT连接同样会消耗客户端的内存。

    对服务器的影响:

    由于服务器一般只需要监听一个固定的端口,所以服务器所能支持的最大并发出数的上限取决于系统套接字描述符fd的大小,以及服务器的内存大小。当服务器主动关闭连接,产生time_wait时,每一个连接需要占用一定大小的内存资源,当TIME_WAIT 状态的连接过多时,会导致消耗的内存增加

    优化time_wait过多的问题
    1、修改内核参数 tcp_tw_reuse:

    net.ipv4.tcp_tw_reuse = 1; //1表示开启,默认是0net.ipv4.tcp_timestamp = 1; // 这个是表示time_wait的时间超过了timstamp就可以重用该端口了

    注意: tcp_tw_reuse 内核参数只在调用 connect() 函数时起作用,所以只能用于客户端(主动连接的一端)。

    tcp_tw_reuse 的作用是:在调用connect()函数时,内核会随机找一个处于TIME_WAIT状态 超过1秒 的连接给新连接复用。(超时时间由 tcp_timestamp设置,默认为 1秒)

    这种方式可以缩短 TIME_WAIT 的等待时间。

    2、修改内核参数 tcp_max_tw_buckets:
    net.ipv4.tcp_max_tw_buckets 参数的默认值为18000,当系统中处于 TIME_WAIT 状态的连接数量超过阈值,系统会将后面的TIME_WAIT连接重置。

    相关推荐

    相关文章