用ss快速识别半开连接需精准过滤状态:ss -ton state fin-wait-1、ss -ton state close-wait、ss -tan state syn-recv;其中orphaned非零即确认内核级socket泄漏,CLOSE-WAIT和FIN-WAIT-2卡住表明应用未主动关闭。

怎么用 ss 快速识别半开连接
半开连接(如 FIN-WAIT-1、CLOSE-WAIT、SYN-RECV)并不只是“暂时还没彻底断开”这么简单,本质上是连接生命周期卡在了中间状态,通常说明要么对端出了异常,要么本端在关闭流程上没有处理到位。排查时也别直接用 ss -t | grep CLOSE 这类模糊匹配——状态字段的位置并不固定,很容易出现漏判,甚至误判。
ss -ton state fin-wait-1:只输出 FIN-WAIT-1 状态,加-o可看超时剩余时间,判断是否已超时却未回收ss -ton state close-wait:CLOSE-WAIT 大量堆积,说明本端收到 FIN 后没调close(),常见于应用 read() 返回 0 后忘记 shutdownss -tan state syn-recv:SYN-RECV 是真正的半连接(三次握手未完成),持续 >100 基本可判定是 SYN Flood 或net.core.somaxconn设置过小
为什么 ss -s 的 orphaned 值非零就是硬泄漏
ss -s 第一行的 orphaned 数值是内核级指标:进程已退出,但 socket 还挂在内核里没释放。它和用户态可见的 Total 不重叠,也不受 TIME-WAIT 影响。一旦 orphaned > 0,基本等于确认泄漏,不是配置问题,是代码缺陷。
- 常见原因:子进程继承了父进程的 socket fd 但没显式 close;信号中断导致 cleanup 跳过;使用了
fork()但没在子进程中关闭监听 socket - 验证方式:
cat /proc/net/sockstat查sockets: used和orphan行,对比是否随时间增长 - 注意:
net.ipv4.tcp_max_orphans是保护阈值,设太高只会延迟 OOM,不能解决根本问题
如何区分半开连接是攻击还是程序 bug
SYN-RECV 高 ≠ 一定被攻击。得结合来源 IP 分布和连接持续时间看:
- 如果
ss -tan state syn-recv输出里源 IP 高度离散(几十上百个不同 C 段),且每个连接存在时间接近 60–120 秒(内核默认tcp_synack_retries超时周期),大概率是 SYN Flood - 如果源 IP 集中在 1–2 个内网段,且连接存在时间极短(<5 秒)又反复出现,更可能是客户端异常断连 + 服务端未设置
SO_LINGER或未处理read() == 0 - 用
ss -tan state syn-recv -i看rto和retrans:若重传次数 >3 且 RTO 持续拉长,说明网络层丢包严重,不是纯协议栈问题
排查时最容易忽略的两个点
先看两点很容易被忽略的细节:其一,ss -t 默认只看 TCP,不会把 UDP 带出来,而不少“半开”现象恰恰更容易藏在 UDP 场景里,比如 DNS 查询发出去后迟迟没响应,既不重试,也不做清理;其二,所有状态过滤的写法必须严格使用小写加连字符,state time-wait 才是正确写法,像 state TIME_WAIT 或 state timewait 这类写法都会直接静默失败,既不报错,也没有任何输出。
真正卡住的半开连接,往往藏在 CLOSE-WAIT 和 FIN-WAIT-2 里——前者代表你收了 FIN 却没发 FIN,后者代表你发了 FIN 却没等到 ACK,这两个状态不会自动超时清理,全靠应用主动干预。