ss 默认不显示未完全初始化的监听套接字(如 so_reuseaddr 占用但未 accept 的状态),而 netstat 显示所有监听项;加 -a 参数可让 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可单独筛选,配合src或dst过滤来源 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 -tulnp → Permission denied。
- 非 root 用户想查自己进程:用
ss -tuln src :$PORT或ss -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 缓冲区使用情况,但多数人连它在哪列都找不到——因为默认不显示。