服务器TIME_WAIT和CLOSE_WAIT区别及解决方案

本文深入解析TCP连接状态,包括TIME_WAIT和CLOSE_WAIT的产生原因及解决策略。TIME_WAIT可通过优化系统内核参数解决,涉及资源回收和连接可靠性;CLOSE_WAIT则需从程序层面排查,确保及时响应并关闭连接。

系统上线之后,通过如下语句查看服务器时,发现有不少TIME_WAIT和CLOSE_WAIT。

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

打印显示如下:

TIME_WAIT 297
ESTABLISHED 53
CLOSE_WAIT 5

     TIME_WAIT:表示主动关闭,通过优化系统内核参数可容易解决。

     CLOSE_WAIT:表示被动关闭,需要从程序本身出发。

     ESTABLISHED:表示正在通信

    通过上网了解,总结如下:

 

一、TIME_WAIT(通过优化系统内核参数可容易解决)

       TIME_WAIT是主动关闭连接的一方保持的状态,对于服务器来说它本身就是“客户端”,在完成一个爬取任务之后,它就会发起主动关闭连接,从而进入TIME_WAIT的状态,然后在保持这个状态2MSL(max segment lifetime)时间之后,彻底关闭回收资源。为什么要这么做?明明就已经主动关闭连接了为啥还要保持资源一段时间呢?这个是TCP/IP的设计者规定的,主要出于以下两个方面的考虑:

        1.防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)

        2.可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。

        解决方案很简单,通过修改/etc/sysctl.conf文件,服务器能够快速回收和重用那些TIME_WAIT的资源  

        

#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭  
net.ipv4.tcp_syncookies = 1  
#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭  
net.ipv4.tcp_tw_reuse = 1  
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭  
net.ipv4.tcp_tw_recycle = 1
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间  
net.ipv4.tcp_fin_timeout=30

        生效,如下命令        

/sbin/sysctl -p

 

二、CLOSE_WAIT(需要从程序本身出发)

       TCP状态转移要点

       TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源.

        客户端TCP状态迁移:        

CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

     

         服务器TCP状态迁移:      

CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

       当客户端开始连接时,服务器还处于LISTENING,客户端发一个SYN包后,他就处于SYN_SENT状态,服务器就处于SYS收到状态,然后互相确认进入连接状态ESTABLISHED。

 

       TIME_WAIT状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的。

        但是CLOSE_WAIT就不一样了,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。个人觉得这种情况,通过服务器内核参数也没办法解决,服务器对于程序抢占的资源没有主动回收的权利,除非终止程序运行。

       什么情况下,连接处于CLOSE_WAIT状态呢?

       答案一:在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态。但是在一些特殊情况下,就会出现连接长时间处于CLOSE_WAIT状态的情况。

        答案二:出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno,如果不是AGAIN,就断开连接。

### 关于大量出现 CLOSE_WAIT TIME_WAIT 的原因及解决方案 #### 1. **CLOSE_WAIT 状态的原因及解决方法** CLOSE_WAIT 是被动关闭连接的一方在接收到对方发送的 FIN 包后进入的状态。如果服务端程序没有正确处理该 FIN 包,导致没有及关闭连接,则会出现大量的 CLOSE_WAIT 状态连接[^2]。 - **原因**: - 程序未正确检测到对方已关闭连接,并未调用 `close()` 函数释放资源。 - 可能由于代码逻辑问题,例如读写操作未检查返回值,或者未正确处理异常情况。 - 程序设计中忽略了对 socket 状态的监控,未能及关闭无用连接。 - **解决方法**: - 在代码中增加对 socket 的状态检查,确保当读取到 EOF(返回值为 0),立即调用 `close()` 函数释放资源。 - 对于异常情况(如 `read` 返回负值),需检查 `errno`,若非 `EAGAIN` 或其他可重试错误,则应关闭连接。 - 使用定器或心跳机制定期检测长连接的有效性,及清理无效连接。 - 示例代码: ```python import socket def handle_connection(conn): while True: data = conn.recv(1024) if not data: # 对方关闭连接 conn.close() # 关闭连接 break if data == b'error': # 模拟异常情况 conn.close() # 异常关闭连接 break ``` #### 2. **TIME_WAIT 状态的原因及解决方法** TIME_WAIT 是主动关闭连接的一方在发送最后一个 ACK 包后进入的状态。此状态会持续 2MSL(最大段生命周期)间,以确保网络中残留的数据包被清除[^4]。 - **原因**: - 主动关闭连接的一方需要等待一段间以确认对方成功接收最后的 ACK 包。 - 如果服务器频繁发起主动关闭连接,可能会导致大量 TIME_WAIT 状态的连接积压。 - **解决方法**: - 调整内核参数以优化 TIME_WAIT 的处理: - 启用 `net.ipv4.tcp_tw_reuse = 1` 允许 TIME_WAIT 状态的 socket 被重用。 - 启用 `net.ipv4.tcp_tw_recycle = 1` 快速回收 TIME_WAIT 状态的 socket(注意:在某些现代 Linux 内核版本中已被废弃)。 - 缩短 `net.ipv4.tcp_fin_timeout` 的默认超间,以减少 TIME_WAIT 状态的持续间。 - 示例配置: ```bash echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_tw_recycle = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_fin_timeout = 10" >> /etc/sysctl.conf sysctl -p ``` - 在高并发场景下,尽量避免频繁主动关闭连接,可通过复用长连接减少 TIME_WAIT 的产生。 ### 总结 大量 CLOSE_WAIT TIME_WAIT 状态的出现可能是由于程序逻辑错误或系统参数未优化所致。通过改进代码逻辑调整内核参数,可以有效减少这些状态的积压,提升系统的性能稳定性[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值