用 ss -tan | awk '$1~/tcp/&&$nf~/syn_recv|fin_wait2|close_wait/{print $nf}' | sort | uniq -c 可统计半开连接数量,其中 syn_recv 表示未完成三次握手、fin_wait2 和 close_wait 可能反映对端异常或应用未关闭连接。

怎么用 netstat 或 ss 统计半开连接(SYN_RECV、TIME_WAIT 等)数量
Linux 本身不直接标记“由于对端异常导致的半开连接”,但可通过 TCP 状态码识别典型半开场景:比如 SYN_RECV(服务端收到 SYN 但未完成三次握手,常因客户端丢包或崩溃)、FIN_WAIT2(本端发 FIN 后等待对端 FIN,若长期存在可能对端异常终止)、CLOSE_WAIT(对端已关闭,本端未调用 close,常见于应用 bug)。这些状态堆积是半开连接的主要线索。
统计命令需过滤 TCP 行 + 按状态分组:
-
ss -tan | awk '{print $1}' | sort | uniq -c | sort -nr—— 快速列出所有 TCP 状态及数量(推荐,比 netstat 更准更快) -
netstat -an | awk '$6 ~ /SYN_RECV|TIME_WAIT|FIN_WAIT2|CLOSE_WAIT/ {print $6}' | sort | uniq -c—— 兼容老系统,但注意netstat在部分发行版中默认不安装且输出格式易受 locale 影响 - 若要排除本地回环和已建立连接,加条件:
ss -tan | awk '$1 ~ /tcp/ && $NF ~ /SYN_RECV|FIN_WAIT2/ && $4 !~ /127\.0\.0\.1|::1/ {print $NF}' | sort | uniq -c
为什么不能只看 TIME_WAIT 就认定是“对端异常”
TIME_WAIT 是正常协议行为(防止旧包干扰新连接),持续约 2×MSL(通常 60 秒),高并发服务必然大量存在。它本身不是故障信号,除非出现以下组合:
- 同一源 IP + 端口频繁复用,且
TIME_WAIT数量突增(可能客户端未复用连接) -
SYN_RECV持续 > 30 秒不下降,且对应源 IP 在防火墙日志中无后续 ACK(说明 SYN 到了,ACK 丢了或没发) -
CLOSE_WAIT数量持续增长,且关联进程 CPU/内存无变化(大概率应用未 close socket)
单独一个状态计数无法归因“对端异常”,必须结合日志、时序、源 IP 分布交叉验证。
从 auth.log、kern.log、iptables 日志里捞半开连接线索
系统日志不会直接写“半开连接”,但会留下对端异常的间接证据:
-
grep "Connection timed out" /var/log/auth.log—— SSH 客户端断连未清理,可能遗留FIN_WAIT2 -
grep -i "reset" /var/log/kern.log | tail -50—— 内核打印 connection reset,常伴随SYN_RECV突降或ESTABLISHED异常关闭 -
grep "DPT=.*DROP" /var/log/iptables.log 2>/dev/null | awk '{print $8}' | sort | uniq -c | sort -nr | head -10—— 若某 IP 被大量 DROP 且之前出现在SYN_RECV中,极可能是网络中间设备拦截或对端防火墙策略变更
注意:iptables 日志需提前开启 LOG 规则,如 -A INPUT -p tcp --syn -j LOG --log-prefix "SYN-LOG: ",否则无 SYN 包记录。
用 shell 脚本做轻量级半开连接分类告警
不要依赖复杂 ELK,一个 20 行脚本能覆盖多数运维场景:
#!/bin/bash SYN_RECV=$(ss -tan state syn-recv | wc -l) FIN_WAIT2=$(ss -tan state fin-wait-2 | wc -l) CLOSE_WAIT=$(ss -tan state close-wait | wc -l) <p>if [ $SYN_RECV -gt 50 ]; then echo "$(date): HIGH SYN_RECV ($SYN_RECV)" >> /var/log/net-alert.log logger -t netwatch "SYN_RECV > 50" fi</p><p>if [ $CLOSE_WAIT -gt 200 ]; then echo "$(date): CLOSE_WAIT surge ($CLOSE_WAIT), check app process" >> /var/log/net-alert.log</p><h1>可追加:lsof -i -n -P | grep CLOSE_WAIT | head -5 >> /var/log/net-alert.log</h1><p>fi</p>
关键点:
- 用
ss -tan state xxx比正则匹配更可靠(避免误匹配字段) - 告警阈值必须按业务调优:Web 服务
SYN_RECV> 50 很危险,但内网 RPC 网关可能常态 200+ - 日志路径写死在
/var/log/net-alert.log,避免写入 /tmp 被清空
真正难的不是统计数字,而是把 SYN_RECV 数值和某次上游 CDN 节点宕机、某批 Android 客户端升级后 TLS 握手失败、某台 LB 的 conntrack 表溢出这三件事串起来——那得靠你记日志时带上下文,而不是等告警再翻。











