用 /proc/pid/fd 追踪进程网络连接
内容提要
本文介绍如何利用Linux的/proc文件系统追踪进程网络连接,无需额外工具。通过/proc/net/tcp获取端口对应的inode号,再遍历/proc/<pid>/fd找到持有该socket的进程。提供两个脚本:按端口查进程和按PID查连接,并解析十六进制地址与端口,附常见端口对照表。
延伸解读
为什么用 inode 而不是直接 grep 进程的 net/tcp
文章指出,/proc/<pid>/net/tcp 是系统全局视图,每个进程都能看到所有 TCP 连接。如果直接 grep 每个进程的 net/tcp,会全部命中,无法区分连接属于哪个进程。正确方法是先从全局 /proc/net/tcp 找到 inode(内核给 socket 的唯一编号),再遍历进程的 /proc/<pid>/fd 找到哪个文件描述符指向这个 inode。这避免了误判,是追踪进程网络连接的关键。
脚本的局限性与注意事项
脚本依赖 /proc 文件系统,仅适用于 Linux。它只处理 TCP4,未涵盖 TCP6 和 UDP。此外,脚本假设端口是十六进制输入,且只查找 LISTEN 状态,对于已建立的连接可能无法通过端口反查进程。使用时需注意权限,某些进程的 fd 可能因权限不足而无法读取。
state 值的实际含义
文章给出了 state 值的部分含义:0A 表示 LISTEN,01 表示 ESTABLISHED,06 表示 TIME_WAIT。理解这些状态有助于判断连接的性质:LISTEN 表示服务正在监听,ESTABLISHED 表示活跃连接,TIME_WAIT 表示连接已关闭但仍在等待。这有助于排查网络问题,例如发现大量 TIME_WAIT 可能表明连接频繁建立和关闭。
Q&A
如何在不安装额外工具的情况下,根据端口号找到对应的进程?
可以通过 /proc 文件系统实现。首先从 /proc/net/tcp 中找到该端口(十六进制)对应的 inode 号,然后遍历 /proc/<pid>/fd 下的所有文件描述符,查找指向该 inode 的 socket 链接,即可找到持有该端口的进程。文章提供了一个 bash 脚本示例。
如何查看一个进程的所有网络连接?
可以遍历 /proc/<pid>/fd 目录,收集所有指向 socket 的 inode 号,然后在 /proc/net/tcp 和 /proc/net/tcp6 中查找这些 inode 对应的连接信息,包括本地地址、远程地址和状态。文章提供了脚本示例,输出类似 TCP4 0.0.0.0:80 -> 0.0.0.0:0 state=0A 的格式。
为什么不能直接 grep 每个进程的 /proc/<pid>/net/tcp 来查找连接?
因为 /proc/<pid>/net/tcp 是系统全局视图,每个进程都能看到所有 TCP 连接,直接 grep 会导致所有进程都命中,无法准确找到持有该连接的进程。正确方法是先从全局 /proc/net/tcp 找到 socket 的 inode 号,再遍历进程的 fd 目录找到指向该 inode 的文件描述符。
在 /proc/net/tcp 中,端口号是如何表示的?如何将十进制端口转换为十六进制?
在 /proc/net/tcp 中,端口号以十六进制表示,例如端口 9000 表示为 2328。转换方法:使用 printf 或 shell 的算术扩展,如 $((16#2328)) 可得到十进制 9000。文章还提供了常见端口对照表,如 80 对应 0050,443 对应 01BB。
在 /proc/net/tcp 中,状态字段的值代表什么?例如 0A 和 01 分别表示什么?
状态字段是十六进制数,0A 表示 LISTEN(监听),01 表示 ESTABLISHED(已建立连接),06 表示 TIME_WAIT。这些值对应 TCP 连接状态。
如何解析 /proc/net/tcp 中的十六进制 IP 地址?
IP 地址以十六进制小端序表示,例如 0100007F 代表 127.0.0.1。解析时,将每两个十六进制字符转换为一个十进制数,并反转字节序。文章中的脚本使用 sed 和 printf 实现,例如将 0100007F 转换为 127.0.0.1。