Linux netstat 与 ss 网络监控实践

2次阅读

ss 看不到 netstat 的 listen 端口,因 ss -l 默认不显示通配符地址监听项且过滤中间状态;应使用 ss -tula 并注意权限、内核接口差异及进程名获取机制。

Linux netstat 与 ss 网络监控实践

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

因为 netstat 默认显示所有监听套接字(包括未绑定具体地址的 0.0.0.0::),而 ss -l 默认只显示已建立监听状态的套接字,且对通配符地址(如 0.0.0.0:22)的呈现逻辑不同。

实操建议:

  • ss -tuln 替代 netstat -tuln —— -t(TCP)、-uudp)、-l(listening)、-n(数字端口)是等效组合
  • 若仍缺端口,加 -ass -tula,否则 ss 会跳过处于 SYN-RECV 或其他中间状态的监听项
  • netstat 可能读取 /proc/net/tcp 等旧接口,而 ss 直接调用 netlink,内核版本较新时后者更准,但某些容器或 chroot 环境下可能因权限缺失漏报

ss 输出里 State 列显示 weird 状态如 syn-recv、fin-wait-1

这些不是错误,而是 ssnetstat 更细粒度地暴露了 TCP 状态机细节。例如 syn-recv 表示服务端已发 SYN+ACK、正等待客户端 ACK(三次握手未完成),常见于被 SYN flood 攻击或客户端异常断连后。

实操建议:

  • 排查连接积:用 ss -tan state syn-recv | wc -l 统计数量,持续 >100 需查防火墙、SYN cookies 是否开启(cat /proc/sys/net/ipv4/tcp_syncookies
  • ss -tan state established 才对应 netstatESTABLISHEDss 不把 CLOSE_WAIT 归入 listening,这点和 netstat -an 行为一致
  • 避免误判:ssstate 过滤支持复合条件,比如 ss -tan '( dport = :80 or dport = :443 )',括号和空格必须保留,否则语法报错

想看某个进程绑定了哪些端口,ps + netstat 组合为什么常失效

因为 netstat -tulpn 依赖 /proc/<pid>/fd/</pid> 符号链接解析,而容器、sudo 启动、seccomp 限制或非 root 用户运行的服务会导致该路径不可读,netstat 就显示 - 或直接跳过进程名。

实操建议:

  • 优先用 ss -tulpn —— 它通过 netlink 获取进程 ID 更可靠,尤其在 systemd 管理的服务中
  • 若仍无进程名,检查是否缺少 cap_net_admincap_net_raw 能力(getpcaps <pid></pid>),或尝试 sudo ss -tulpn
  • 替代方案:lsof -i -P -n -sTCP:LISTEN,但开销大、默认不装、且在某些内核(如 Alpine 的 musl)上无法识别 socket 类型

ss 命令输出列太多记不住,怎么快速定位关键字段

ss 默认列顺序固定但冗长,实际只需关注 Recv-Q/Send-Q、State、Local Address:Port、Peer Address:Port、Process(如果可用)。其余如 Timer、UID、Inode 多数场景可忽略。

实操建议:

  • -o 显示 timer 仅用于诊断重传问题,普通监控不用加;-e(扩展)会强制显示 UID 和 Inode,但需 root 权限,且容易让输出变宽难读
  • 简化输出:用 ss -tunl | awk '{print $1,$4,$5}' 提取协议、本地地址、进程(注意 $5 在无进程时为空)
  • 别依赖列号硬编码:不同版本 ss(如 iproute2 5.15 vs 6.1)可能微调列顺序,建议用 ss -h 确认当前字段含义,或改用 --no-header + column -t 对齐再切

真正麻烦的是 UDP 套接字的状态不可见——ss -uln 里所有 UDP 都标为 UNCONN,哪怕程序已经 bind()recvfrom() 中。这时候不能靠 State 判断“是否活跃”,得结合 /proc/net/udpst 字段或用 tcpdump 抓包验证。

text=ZqhQzanResources