你的位置:首页 > Java教程

[Java教程]TIME_WAIT、 CLOSE_WAIT

 内容提要

  • TCP连接释放的过程
  • TIME_WAIT
    • 大量TiME_WAIT的后果
    • 解决方案
  • CLOSE_WAIT
    • 大量CLOSE_WAIT的后果
    • 解决方案

 

 

TCP 连接释放的过程

 

 

图中,A是主动关闭的一方,B是被动关闭的一方。

 从图中可以看出,如果处于TIME_WAIT状态,说明是主动关闭的。如果处于CLOSE_WAIT,说明是被动关闭的。

 

TIME_WAIT

         从图上看出,TIME_WAIT状态下,会有2个MSL(最大报文存活时间)的等待时间,之后才会处于CLOSED状态,并释放资源。

 

 

         为了保证A发送的最后一个ACk报文段能够到达B,其实就是为了让B真正的关闭,这样才能够保证连接的双方都关闭。毕竟是全双工的通信,总不能出现A到B的连接是关闭的,B到A的连接是打开的,这样只能算是半关闭状态。

MSL 的默认值是120s,也就是2分钟,所以2MSL就是4分钟。也就是说主动关闭的一方,会等待4分钟才会释放相关资源。

 

出现TIME_WAIT会带来的后果

1) 如果客户端出现了大量的TIME_WAIT,那么在这4分钟之内,想要再使用该Socket绑定的端口,肯定会报BindException了。

2) 如果服务端出现了大量的TIME_WAIT,则服务的性能会下降,因为底层有大量的Sturct  Socket没有释放,占内存,在用户量很大时,会很卡。

3) 服务端重启时,ServerSocket绑定的端口可能会处于TIME_WAIT状态,也是会出现BindException异常的。

 

TIME_WAIT解决方案

         从程序设计的角度讲:

                 服务端最好不要(或者少)出现TIME_WAIT状态,毕竟这个问题是不可避免的。也就是要把TIME_WAIT分散到客户端,即让客户端主动关闭连接。

         从运维的角度来考虑讲:

                 就需要对操作系统的配置做调整了:

net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间,单位s

  

CLOSE_WAIT

         根据上面的TCP连接释放过程中可以看出,如果一方出现了CLOSE_WAIT状态,说明在连接被动关闭后,没有发送FIN报文段到对方。

        

    

 

         默认情况下,操作系统设定的Keepalive时间是2小时。

 

大量CLOSE_WAIT会带来的后果

         如果发生在客户端,说明连接是被服务端关闭的。客户端的这些端口在这CLOSE_WAIT状态内,是不能够使用了。如果要使用,应会报BindExcepion了。

         如果发生在服务端,说明是客户端关闭的,服务端同样会变的更慢了。出现这种情况就要在服务端找原因了。

 解决方案

         从程序设计角度讲

             1) 在另一端出现关闭了连接后,出现CLOSE_WAIT的一端为什么没有相应的执行关闭连接操作。

             2) 如果这种现象发生的客户端,还要去查为什么服务端要关闭这些连接,服务端该不该关闭。

                  如果从代码上去解决这种问题,就应该是执行Socket(或者SocketChannel)的close()方法。执行这个方法时,才会去发送FIN报文段。

        

        从运维的角度讲

tcp_keepalive_time :INTEGER默认值是7200(2小时)当keepalive打开的情况下,TCP发送keepalive消息的频率。(由于目前网络攻击等因素,造成了利用这个进行的攻击很频繁,曾经也有cu的朋友提到过,说如果2边建立了连接,然后不发送任何数据或者rst/fin消息,那么持续的时间是不是就是2小时,空连接攻击? tcp_keepalive_time就是预防此情形的.我个人在做nat服务的时候的修改值为1800秒)tcp_keepalive_probes:INTEGER默认值是9TCP发送keepalive探测以确定该连接已经断开的次数。(注意:保持连接仅在SO_KEEPALIVE套接字选项被打开是才发送.次数默认不需要修改,当然根据情形也可以适当地缩短此值.设置为5比较合适)tcp_keepalive_intvl:INTEGER默认值为75探测消息发送的频率,乘以tcp_keepalive_probes就得到对于从开始探测以来没有响应的连接杀除的时间。默认值为75秒,也就是没有活动的连接将在大约11分钟以后将被丢弃。(对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值,15是个比较合适的值)