直接读/proc/net/tcp更可靠,因其是内核实时导出的原始连接表,不依赖用户态工具解析逻辑或特权;但需手动转换十六进制地址端口(如0100007f:0016→127.0.0.1:22)、查状态码(0a=listen)、区分tcp/tcp6,并注意cgroup v2权限限制。

为什么直接读/proc/net/tcp比用netstat或ss更可靠?
因为/proc/net/tcp是内核实时导出的原始连接表,不依赖用户态工具的解析逻辑或权限提升(比如ss -tuln在某些容器里可能因缺少cap_net_admin而漏掉监听端口)。但它的字段全是十六进制+十进制混合,且地址/端口需手动转换——这是多数人卡住的第一步。
/proc/net/tcp每行字段怎么对应实际连接信息?
以典型一行为例:
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
关键字段解析:
-
local_address:格式为0100007F:0016,前8位是IP(小端序十六进制),后4位是端口(小端序)→0100007F→0x7F000001→127.0.0.1;0016→0x16→22 -
rem_address同理,00000000:0000表示监听状态(未建立连接) -
st是状态码:0A=LISTEN,01=ESTABLISHED,06=CLOSE_WAIT等(查include/net/tcp_states.h或man 7 tcp) -
inode可用来关联/proc/[pid]/fd/下的socket文件(需遍历所有进程)
如何用C++安全读取并解析/proc/net/tcp?
不能直接用std::ifstream逐行读——文件无换行符结尾、最后一行可能被截断,且多线程下/proc文件可能动态变化。推荐做法:
- 用
open()+read()一次性读完整文件(/proc/net/tcp通常 - 跳过第一行(表头),用
strtok_r或std::istringstream按空格分割,注意字段数可能不齐(如uid字段缺失时会少一列) - IP转换函数示例:
uint32_t ip = std::stoul("7F000001", nullptr, 16); uint8_t a = ip & 0xFF; uint8_t b = (ip >> 8) & 0xFF;→a.b.c.d - 端口转换:
uint16_t port = std::stoul("0016", nullptr, 16);
为什么解析结果和ss -tuln对不上?
常见原因有三个:
-
/proc/net/tcp只包含IPv4 TCP,IPv6走/proc/net/tcp6,得分开读——漏掉tcp6会导致监听在::1或::的连接丢失 - 状态码
st值是十六进制字符串,不是十进制,"0A"≠10,而是10(十进制),对应TCP_LISTEN - 某些内核版本(如5.10+)在cgroup v2环境下,非root进程读
/proc/net/tcp可能只看到本cgroup内的连接,需确认运行权限和命名空间
真正麻烦的是把inode反查到进程——得遍历/proc/[0-9]*/fd/,对每个socket:[12345]链接做readlink比对,这步开销大且需readdir权限,多数监控场景其实只关心IP/端口/状态就够了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











