Linux netstat 与 ss 网络监控实战

1次阅读

ss 默认不显示未完全初始化的监听套接字(如 so_reuseaddr 占用但未 accept 的状态),而 netstat 显示所有监听项;加 -a 参数可让 ss 显示全部,包括此类监听项。

Linux netstat 与 ss 网络监控实战

netstat 显示的 LISTEN 端口为什么 ss 看不到?

因为 netstat 默认显示所有监听套接字(包括未绑定具体地址的 0.0.0.0::),而 ss 默认只显示已建立连接或处于监听状态但“有实际绑定行为”的套接字——更准确地说,ss -l 会过滤掉某些内核未完全初始化的监听项,尤其是被 SO_REUSEADDR 占用但尚未调用 accept() 的监听队列空闲状态。

  • 真实场景:nginx 启动后 netstat -tlnp | grep :80 能看到,但 ss -tlnp | grep :80 没输出 → 很可能是 Nginx 还没完成 socket 绑定流程,或用了 deferred accept(如 listen 80 deferred;
  • 解决办法:加 -a 参数让 ss 显示所有状态,包括未完成初始化的监听项:ss -tlnap
  • netstat 已废弃多年,内核接口依赖 /proc/net/,而 ss 直接读取 nl(netlink)接口,结果更实时,但也更“严格”

ss 输出里 State 列的 syn-recv 是什么鬼?

这不是连接已建立的状态,而是 TCP 三次握手卡在第二步:服务端发了 SYN+ACK,但没收到客户端的 ACK 回应。常见于被防火墙拦截、网络丢包、或客户端异常中断。

  • 不是 bug,是正常 TCP 状态机的一部分;但大量 syn-recv 积(尤其搭配高 SYN queue full 日志)说明服务端可能遭受 SYN Flood 攻击,或 net.ipv4.tcp_max_syn_backlog 设得太小
  • ss -nt state syn-recv 可单独筛选,配合 srcdst 过滤来源 IP:ss -nt state syn-recv dst 192.168.1.100
  • netstat 不直接暴露这个状态,它把这类连接归进 LISTEN 或干脆不显示,容易误判连接健康度

为什么 ss -tuln 比 netstat -tuln 快那么多?

根本原因不在命令本身,而在数据源:netstat 要逐个解析 /proc/net/tcp/proc/net/udp 等文本文件,还要查 /proc/PID/fd/ 反推进程名,IO 和字符串处理开销大;ss 用 netlink socket 直接从内核内存结构读取,跳过文件解析和权限检查。

  • 实测:在 2000+ 并发连接的机器上,netstat -tuln 耗时常超 800ms,ss -tuln 通常
  • 兼容性注意:极老内核(ss 功能,但主流发行版(CentOS 7+/Ubuntu 16.04+)都无问题
  • 别迷信 -r(解析域名):加了它,ss 会反向 DNS 查询每个 IP,速度反而比 netstat 还慢,线上排查一律用 -n

ss 怎么看某个进程打开的所有 socket?

-p 参数,但它需要 root 权限,且依赖 /proc/PID/fd/ 下的符号链接可读。普通用户执行会报错:ss -tulnpPermission denied

  • 非 root 用户想查自己进程:用 ss -tuln src :$PORTss -tuln dport = :$PORT 定位端口,再结合 lsof -i :$PORT(如果装了 lsof)
  • -p 实际调用的是 getpidof() + readlink(/proc/PID/fd/X),若目标进程设了 PR_SET_NO_NEW_PRIVS 或挂载了 hidepid=2 的 /proc,即使 root 也看不到进程名,只显示 -
  • 替代方案:用 cat /proc/net/{tcp,udp} 手动匹配 inode 列,再遍历 /proc/*/fd/ 查哪个进程打开了该 inode —— 繁琐但绕过权限限制

真正难的从来不是记命令参数,而是理解每个字段背后对应的内核数据结构和 TCP 状态机流转。比如 ss 输出里的 skmem 字段(需 -e)反映 socket 缓冲区使用情况,但多数人连它在哪列都找不到——因为默认不显示。

text=ZqhQzanResources