服务器拒绝访问问题定位及修复

本文探讨了服务器连接中常见的TIME_WAIT和CLOSE_WAIT状态,分析了这两种状态产生的原因及影响,并提供了具体的优化方案,包括调整系统内核参数以及改进应用程序逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一:问题定位
1.使用top查看当前系统资源占用情况,包括cpu、内存、硬盘
2.查看系统连接数据
netstat -an | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
3.系统存在大量TIME_WAIT和CLOSE_WAIT
4.TIME_WAIT是系统资源调用,大量访问冲击时,系统会存在大量带消化处理的连接,此时连接的装填都是TIME_WAIT
5.CLOSE_WAIT是程序资源延迟释放的动作,正常情况下,服务器会针对web访问进行webcache,但是只是针对每一种请求缓存一个,这种情况是没有问题的
常见存在大量的CLOSE_WAIT的连接主要的问题是资源释放不及时,包括关闭数据连接但仍有资源在占用,关闭MQ连接顺序不当,本机关闭连接后,系统无法进行握手操作导致wait
第二:服务器TIME_WAIT和CLOSE_WAIT区别及解决方案
系统上线之后,通过如下语句查看服务器时,发现有不少TIME_WAIT和CLOSE_WAIT。
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in Sprint a, S[a]}'打印显示如下:TIME_WAIT 297ESTABLISHED 53CLOSE_WAIT 5 TIME_WAIT:表示主动关闭,通过优化系统内核参数可容易解决CLOSE_WAIT:表示被动关闭,需要从程序本身出发ESTABLISHED:表示正在通信关于TIME_WAIT和CLOSE_WAIT的解决方案如下:一、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,就断开连接。
<think>我们正在讨论服务器拒绝TCP连接的原因及排查方法。根据引用内容,我们可以从多个角度分析原因,包括防火墙设置、TCP连接状态异常、系统资源限制等。下面将详细展开。</think>### 服务器拒绝 TCP 连接的原因及排查方法 服务器拒绝 TCP 连接通常发生在连接建立阶段(三次握手),主要涉及以下环节: #### **一、常见拒绝原因** 1. **防火墙拦截** - 规则配置阻止特定端口访问(如 `iptables -A INPUT -p tcp --dport 80 -j DROP`)[^1] - 安全策略限制来源 IP(如仅允许特定 IP 访问) 2. **服务未运行** - Web 服务器(如 Nginx/Apache)未启动 - 端口监听异常(`netstat -tuln | grep :80` 无输出) 3. **TCP 参数配置问题** - `net.ipv4.tcp_tw_recycle=1` NAT 冲突导致 SYN 被丢弃[^5] - `net.ipv4.tcp_syncookies=0` 时 SYN 洪水攻击防护失效 - 连接数超过 `net.core.somaxconn` 限制(默认 128) 4. **异常连接状态堆积** - **TIME_WAIT 过多**:短连接频繁,耗尽可用端口 *解决方案*: ```bash sysctl -w net.ipv4.tcp_tw_reuse=1 # 重用 TIME_WAIT 连接 sysctl -w net.ipv4.tcp_fin_timeout=30 # 缩短 FIN 等待时间 ``` - **CLOSE_WAIT 堆积**:应用未正确关闭连接[^2] *特征*:`netstat` 显示大量 `CLOSE_WAIT` 5. **资源耗尽** - 文件描述符超过限制(`ulimit -n`) - 内存或 CPU 过载导致新建连接失败 --- #### **二、系统性排查流程** 1. **验证服务状态** ```bash # 检查端口监听 ss -ltn | grep :80 # 测试本地连接 telnet 127.0.0.1 80 ``` 2. **检查防火墙规则** ```bash iptables -L -n -v # 查看规则及匹配计数 ufw status # Ubuntu 防火墙 ``` 3. **分析连接状态** ```bash netstat -n | awk '/^tcp/ {print $6}' | sort | uniq -c ``` 输出示例: ``` 120 ESTABLISHED 350 TIME_WAIT # 需优化参数 40 CLOSE_WAIT # 检查应用代码 ``` 4. **审查内核参数** ```bash sysctl -a | grep -E 'tw_reuse|fin_timeout|somaxconn' ``` 关键参数建议: ```bash net.ipv4.tcp_tw_reuse = 1 # 启用 TIME_WAIT 重用 net.core.somaxconn = 1024 # 增大连接队列 net.ipv4.tcp_max_syn_backlog = 2048 ``` 5. **抓包分析握手过程** ```bash tcpdump -i eth0 'tcp port 80 and (tcp[tcpflags] & tcp-syn != 0)' ``` - 正常流程:SYN → SYN-ACK → ACK - 拒绝表现:客户端 SYN 无响应或收到 RST --- #### **三、针对性解决方案** | 问题类型 | 解决方案 | |-------------------|--------------------------------------------------------------------------| | **防火墙拦截** | 添加放行规则:`iptables -I INPUT -p tcp --dport 80 -j ACCEPT` | | **TIME_WAIT 过多**| 优化参数:`sysctl -w net.ipv4.tcp_tw_reuse=1` 并减少短连接 | | **CLOSE_WAIT 堆积**| 修复应用:确保 socket 调用 `close()` 释放资源[^2][^3] | | **连接队列满** | 增大 `net.core.somaxconn` 和 `net.ipv4.tcp_max_syn_backlog` | | **NAT 环境问题** | 禁用 `net.ipv4.tcp_tw_recycle`(Linux 4.1+ 已移除此参数) | > **关键提示**: > - CLOSE_WAIT 持续增长通常是 **应用程序 Bug**,需检查代码是否遗漏 socket 关闭[^2] > - 生产环境建议使用连接池减少频繁建连 > - 高并发场景启用 SYN cookies:`sysctl -w net.ipv4.tcp_syncookies=1` --- #### **四、进阶工具** 1. **连接跟踪** ```bash conntrack -L -d 目标IP # 查看连接跟踪记录 ``` 2. **性能监控** ```bash dstat -tcn # 实时查看 TCP 连接数变化 ``` 3. **压力测试** ```bash ab -c 100 -n 1000 http://server/ # 模拟并发测试 ``` 通过上述分层排查,可精准定位拒绝原因。典型场景中,**防火墙配置**和**应用未释放连接**(CLOSE_WAIT)占比超过 70%[^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值