网络连接无法释放—— CLOSE_WAIT

关键字:TCP ,CLOSE_WAIT, Java, SocketChannel

 

问题描述:最 近性能测试碰到的一个问题。客户端使用NIO,服务器还是一般的Socket连接。当测试进行一段时间以后,发现服务器端的系统出现大量未释放的网络连 接。用netstat -na查看,连接状态为CLOSE_WAIT。这就奇怪了,为什么Socket已经关闭而连接依然未释放。

 

解决:Google了半天,发现关于CLOSE_WAIT的问题一般是C的,Java似乎碰到这个问题的不多(这有一篇不错的,也是解决CLOSE_WAIT的,但是好像没有根本解决,而是选择了一个折中的办法)。接着找,由于使用了NIO,所以怀疑可能是这方面的问题,结果找到了这篇。顺着帖子翻下去,其中有几个人说到了一个问题—— 一端的Socket调用close后,另一端的Socket没有调用close.于是查了一下代码,果然发现Server端在某些异常情况时,没有关闭Socket。改正后问题解决。

时间基本上花在Google上了,不过也学到不少东西。下面为一张TCP连接的状态转换图:

 

 

说明:虚线和实线分别对应服务器端(被连接端)和客户端端(主动连接端)。

结合上图使用netstat -na命令即可知道到当前的TCP连接状态。一般LISTEN、ESTABLISHED、TIME_WAIT是比较常见。

 

分析:

上面我碰到的这个问题主要因为TCP的结束流程未走完,造成连接未释放。现设客户端主动断开连接,流程如下

 

       Client                            消息                                    Server

         close()
                                      ------ FIN ------->
        FIN_WAIT1                                                         CLOSE_WAIT
                                      <----- ACK -------
        FIN_WAIT2 
                                                                                  close()
                                       <------ FIN ------                     
        TIME_WAIT                                                       LAST_ACK      

                                      ------ ACK ------->  
                                                                                   CLOSED
           CLOSED

 

如上图所示,由于Server的Socket在客户端已经关闭时而没有调用关闭,造成服务器端的连接处在“挂起”状态,而客户端则处在等待应答的状态上。此问题的典型特征是:一端处于FIN_WAIT2 ,而另一端处于CLOSE_WAIT. 不过,根本问题还是程序写的不好,有待提高。

 
网络编程中,当客户端向服务器发送请求后,服务器会创建一个套接字用于处理该请求,并在处理完成后关闭该套接字。如果客户端在服务器关闭套接字之前关闭了连接服务器上的套接字就会进入CLOSE_WAIT状态。这种情况下,如果服务器上存在大量CLOSE_WAIT状态的套接字,就会导致服务器出现性能问题。 要快速释放CLOSE_WAIT状态的套接字,有以下几种方法: 1. 调整TCP的超时参数 可以通过修改TCP的超时参数来加速CLOSE_WAIT状态的套接字释放。具体来说,可以通过调整以下参数: - tcp_fin_timeout:控制发送FIN包后等待对方回复ACK包的时间,默认为60秒,可以缩短该时间来加速CLOSE_WAIT状态的套接字释放。 - tcp_keepalive_time:控制多长时间后发送TCP的Keepalive包,用于检测连接是否已经断开,默认为7200秒,可以缩短该时间来加速CLOSE_WAIT状态的套接字释放。 2. 使用SO_REUSEADDR选项 可以在服务器程序中设置SO_REUSEADDR选项,该选项可以让套接字在关闭后立即释放。具体来说,可以在服务器程序中添加以下代码: ``` int reuse = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); ``` 3. 调整系统内核参数 可以通过修改系统内核参数来加速CLOSE_WAIT状态的套接字释放。具体来说,可以调整以下参数: - net.ipv4.tcp_fin_timeout:与tcp_fin_timeout参数含义相同,控制发送FIN包后等待对方回复ACK包的时间。 - net.ipv4.tcp_keepalive_time:与tcp_keepalive_time参数含义相同,控制多长时间后发送TCP的Keepalive包。 - net.ipv4.tcp_max_tw_buckets:控制系统最多允许多少个同时处于TIME_WAIT状态的套接字,默认为180000,可以适当增大该值来减少CLOSE_WAIT状态的套接字数量。 以上是一些快速释放CLOSE_WAIT状态的套接字的方法,具体方法应根据实际情况选择。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值