nethogs原理

33 阅读5分钟

nethogs 是一个强大的 Linux/Unix 命令行工具,用于按进程实时监控网络带宽使用情况。与其他工具(如 iftop 看接口流量、iptraf 看连接流量)不同,它的核心价值在于告诉你哪个进程在消耗网络带宽。

其核心原理可以分解为以下几个关键步骤:

  1. 嗅探网络流量 (Packet Sniffing with libpcap ):
    • nethogs 使用 libpcap 库(也是 tcpdumpwireshark 等工具的基础)来捕获(嗅探)流经指定网络接口(如 eth0 wlan0 )的原始网络数据包
    • 它需要以 root 权限(如使用 sudo)运行,因为直接访问网络接口进行嗅探需要特权。
    • tcpdump 存储完整数据包不同,nethogs 摄取的目的是快速分析和统计
  1. 将流量关联到进程 (Process Associated Traffic - PAT):
    这是 nethogs 的核心魔法和价值所在。它通过以下步骤将捕获的数据包映射到生成或接收它们的进程上:
    • 解析数据包: 对捕获的数据包进行解析,提取关键的传输层信息:
      • 协议: TCP 或 UDP。
      • 源 IP 地址和端口
      • 目标 IP 地址和端口
    • 查询 /proc/net 目录: Linux 内核在 /proc/net 目录下的文件(如 /proc/net/tcp, /proc/net/udp, /proc/net/tcp6, /proc/net/udp6) 动态地暴露了系统当前所有活动的网络连接状态信息。
      • nethogs 读取这些文件,找到与它捕获的数据包中的 源 IP:源端口 <-> 目标 IP:目标端口 元组(或相反的入站元组)匹配的连接条目。
      • 对于每个连接条目,/proc/net 文件都包含一个至关重要的字段:inode number。 这个 inode 代表内核中标识该特定网络套接字的唯一标识符
    • 解析 /proc/PID/fd/ 目录: 遍历 /proc 目录下代表运行进程的所有 PID 目录(/proc/1234/ 代表 PID 1234)。
      • 在每个进程的 /fd/ (文件描述符) 目录下,nethogs 查找指向 socket:[inode] 的符号链接。
      • 例如 lrwx------ 1 root root 64 May 27 10:00 4 -> socket:[123456789]
      • 核心映射: 当找到匹配步骤 2 中从 /proc/net 文件得到的那个 inode number (如 123456789) 的符号链接时,nethogs 就确定了拥有这个符号链接的进程(即包含该 /proc/PID/ 目录的进程 PID)就是使用这个特定套接字的进程。
    • 统计流量: 一旦数据包的套接字 inode 被映射到一个具体的 PID,nethogs 就会将该数据包的大小(包括链路层头部开销)累加到该进程的统计信息中:
      • 发送 (Sent/SEND): 增加到进程的发送字节/包计数。
      • 接收 (Received/RECV): 增加到进程的接收字节/包计数。
  1. 过滤和聚合:
    • nethogs 通常会忽略非 IP 流量(如 ARP)、非常小的控制帧等,专注于实际的数据传输。
    • 它按进程(有时也按进程创建的不同连接 - 默认聚合到一个进程条目)聚合统计流量数据。
  1. 实时显示和更新:
    • nethogs 运行在一个循环中:
      • 捕获一段时间的流量(或达到一定数量包)。
      • 执行上述的关联和统计逻辑。
      • 清除屏幕上一次的输出。
      • 刷新显示最新排序的结果: 根据总带宽(发送+接收)或其他可选排序方式列出进程及其实时带宽(KB/s, MB/s)和累计字节数。默认更新间隔约为每秒一次。

图解流程简化:

[捕获原始流量 (libpcap)]  ---->  解析包 (源:IPort, 目标:IPort, 协议)
                                    |
                                    ˅
[检查 /proc/net/tcp(或 /proc/net/udp 等)] ---->  匹配连接条目,获取套接字 inode (X)
                                    |
                                    ˅
[遍历 /proc/*/fd/]  ---->  查找 `socket:[X]`              ----> 找到!PID 是 N
                                    |
                                    ˅
[更新 PID N 的统计]      <---- (发送包大小加到 PID N SEND, 接收包大小加到 PID N RECV)
                                    |
                                    ˅
                        [每秒:清屏显示 PID 列表(按总带宽降序)]
                                    |
                                    ˅
                                继续循环...

关键技术和依赖:

  • libpcap : 用于低层数据包捕获。
  • Linux /proc 文件系统: 提供动态访问内核数据结构(进程列表、进程打开的文件描述符列表、系统网络状态/套接字列表)。
  • Inode 绑定: 利用套接字在内核中表示为具有唯一 inode 的特殊文件,并通过 /proc/PID/fd/ 目录暴露所有进程打开的 “文件”(包括套接字)这一特性。

优势和局限性:

  • 优势:
    • 直接按进程显示网络带宽,是诊断“谁在占用带宽?”问题的利器。
    • 无需特殊内核模块或配置。
    • 实时性强。
  • 局限性:
    • 需要 Root 权限(因为需要网络嗅探)。
    • 可能在极高的网络负载下性能不佳(过多包处理开销)。
    • 主要处理 TCP/UDP。对于 raw socket、ICMP 或特殊隧道可能跟踪不完全或不跟踪。
    • 某种程度上是“基于连接”的统计。对于非常短命的连接或某些当进程终止后连接未及时关闭的情况,关联可能不够精确。
    • 在容器化环境(如 Docker/K8s)中,可能看到的是宿主机上容器运行时(如 containerd-shim, docker-proxy, cri-o 等)的流量,而不是容器内部的实际应用进程(尽管新的 nethogs 版本和特定内核配置正在改进容器内的可见性)。
    • 无法像 tcpdump/wireshark 那样解析应用层协议内容。

总结:
nethogs 的工作原理本质上是将 libpcap 捕获到的网络数据与 Linux /proc 文件系统提供的进程文件和套接字信息(通过 inode 关联)进行实时匹配。这种精巧的结合使得它能够独一无二地展示每个进程消耗的网络带宽。理解 /proc/net/proc/PID/fd/ 是实现这一功能的关键。