/proc/net/ 是 Linux 内核暴露 socket 状态的最底层、最真实入口,直接读取 tcp/tcp6/udp/udp6/unix 等纯文本文件可获取实时快照;状态码为十六进制(如 01=ESTABLISHED、0A=LISTEN),需结合内核文档解析,且字段顺序固定但无表头。

直接读取 /proc/net/ 下的原始 socket 文件
Linux 内核把每个协议栈的套接字状态都以纯文本形式暴露在 /proc/net/ 目录下,这是最底层、最真实的视图,不经过任何用户态工具解析。你看到的就是内核当前维护的 socket 表快照。
关键文件包括:/proc/net/tcp、/proc/net/tcp6、/proc/net/udp、/proc/net/udp6、/proc/net/unix。其中前四个是网络套接字,最后一个为本地 Unix 域套接字。
-
/proc/net/tcp每行第 4 列是十六进制状态码(如01= ESTABLISHED,0A= LISTEN),不是字符串,需手动查表或用awk '($4 == "01")'过滤 -
/proc/net/unix第 7 列是引用计数(refs),第 8 列是连接状态(CONND/UNCONN/LISTEN),第 9 列是路径(对抽象 socket 是 @ 开头) - 字段顺序固定但无表头,不同内核版本可能微调;建议先
head -1 /proc/net/tcp看列数,再对照 tcp_states.h 理解状态码
用 ss 查看带进程和内核状态映射的 socket
ss 不是封装 netstat,而是直接读取 /proc/net/ 并做语义化翻译,因此它能还原出更贴近内核意图的状态(比如区分 SYN-SENT 和 SYN-RECV),还能关联进程。
- 加
-tuln看监听端口时,State列显示的是人类可读状态(LISTEN、ESTAB),但背后仍来自/proc/net/tcp的第 4 列 - 加
-p需要 root 权限,输出里users:(("nginx",pid=1234,fd=6))中的fd=6是该进程打开的文件描述符号,对应/proc/1234/fd/6→socket:[123456],而123456就是该 socket 在内核中的唯一 inode 号,可在/proc/net/{tcp,udp}中搜索这一数字(第 10 列)定位原始行 - 用
ss -i可看到 TCP socket 的内核参数快照:ts sack(时间戳与选择性确认)、rtt:123/45(RTT 与 RTTVAR)、cwnd:10(拥塞窗口)等,这些字段直接来自struct tcp_sock
避免依赖 netstat 解析 socket 状态
netstat 是基于旧版 /proc/net/ 格式写的,对较新内核(尤其是 4.15+)中新增的字段或状态支持滞后,且默认会尝试反向 DNS 解析主机名(即使加了 -n,某些场景下仍触发),导致延迟或卡住。
- 例如在高并发场景下执行
netstat -tuln,可能因遍历全部/proc/*/fd/导致系统负载突增;而ss -tuln是单次读取/proc/net/,开销低一个数量级 -
netstat对CLOSE_WAIT的判断逻辑较粗(只看状态码),而ss能结合recv-q是否非零进一步提示“对方已关闭、本方未调用 close” - 很多发行版(如 Alpine、CentOS Stream 9+)已默认不安装
net-tools,netstat不再预置,强行装反而引入过时依赖
快速定位异常 socket 的内核线索
当怀疑 socket 泄漏、TIME_WAIT 过多或连接卡死时,不能只看表面状态,得往内核层面挖。
- 查
TIME_WAIT数量:直接awk '$4 == "06" {n++} END {print n+0}' /proc/net/tcp(06是十六进制 TIME_WAIT),比ss -s的汇总更准,因为后者可能漏掉tcp6或统计时机偏差 - 查 socket 内存占用:
cat /proc/net/sockstat输出里的TCP: inuse 39 mem 3中mem是页数(每页 4KB),inuse是当前分配的 socket 数,两者比值过高说明有大量小包堆积 - 查本地端口耗尽风险:对比
cat /proc/sys/net/ipv4/ip_local_port_range与ss -tan | awk '{print $4}' | cut -d':' -f2 | sort -n | uniq -c | sort -nr | head -5,看高频复用端口是否逼近上限
真正难的不是查到状态,而是理解某一行 /proc/net/tcp 数据背后的内核对象生命周期——比如一个 01 状态的 socket,其 inode 号是否能在 /proc/[pid]/fd/ 下被某个存活进程引用,否则就是孤儿 socket,得查 /proc/sys/net/ipv4/tcp_fin_timeout 是否过短或应用未正确 shutdown。











