为了获得特定于接口的统计信息,已经提出的方法可以正常工作。
我将尝试为您的第二个请求提出解决方案:
知道哪个程序正在使用该带宽也很有帮助,但到目前为止我还没有看到任何可以做到这一点的东西。
如前所述,nethogs打印进程特定的统计信息。据我所知,没有简单的方法可以访问这些值,/proc
因此我将解释 nethogs 如何实现这一点。
考虑一个具有 pid PID 的进程,nethogs 首先检索该进程打开的所有套接字的列表,列出 /proc/PID/fd 的内容:
➜ ~ [1] at 23:59:31 [Sat 15] $ ls -la /proc/21841/fd
total 0
dr-x------ 2 marco marco 0 Nov 15 23:41 .
dr-xr-xr-x 8 marco marco 0 Nov 15 23:41 ..
lrwx------ 1 marco marco 64 Nov 15 23:42 0 -> /dev/pts/15
l-wx------ 1 marco marco 64 Nov 15 23:42 1 -> /dev/null
lrwx------ 1 marco marco 64 Nov 15 23:41 2 -> /dev/pts/15
lrwx------ 1 marco marco 64 Nov 15 23:42 4 -> socket:[177472]
这里我们只有一个套接字,177472 是 inode 号。我们会在这里找到所有类型的套接字:TCPv4、TCPv6、UDP、netlink。在这种情况下,我将只考虑 TCPv4。
一旦收集了所有的 inode 编号,就会为每个套接字分配一个唯一标识符,即(IP_SRC, PORT_SRC, IP_DEST, PORT_DEST)
. 当然,与 PID 的配对也会被存储。(IP_SRC, PORT_SRC, IP_DEST, PORT_DEST)
可以读取元组来检索/proc/net/tcp
(对于 TCPv4)。在这种情况下:
➜ ~ [1] at 0:06:05 [Sun 16] $ cat /proc/net/tcp | grep 177472
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
38: 1D00A8C0:1F90 0400A8C0:A093 01 00000000:00000000 00:00000000 00000000 1000 0 177472 1 f6fae080 21 4 0 10 5
地址表示为 IP:PORT,IP 表示为 4 字节的 LE 编号。然后,您可以构建一个key->value
结构,其中键是(IP_SRC, PORT_SRC, IP_DEST, PORT_DEST)
PID,值是 PID。
此时,nethogs 使用 libpcap 捕获所有网络流量。当它检测到 TCP 数据包时,它会尝试将元组(IP_SRC_PACKET, PORT_SRC_PACKET, IP_DEST_PACKET, PORT_DEST_PACKET)
与表内的所有连接进行匹配。当然它必须尝试交换 SRC 和 DEST,数据包可能是传入 (DL) 或传出 (UL)。如果它处理了一个连接,它会检索该连接所属进程的 PID,并将 TCP 有效负载的大小添加到 TX 或 RX 计数器。通过捕获每个数据包时更新的字节数,可以轻松计算每个进程的传输速度。
理论上,这可以在 python 中使用 pypcap 实现,尽管它需要一些工作。我试图实现一些东西,但它非常缓慢,而且需要更多的工作才能使用。我只监控一个 PID,一个连接,没有更新连接表,但是超过 3MB/s 我的脚本无法跟上网络流量。
如您所见,这并非微不足道。解析现有工具的输出可能会带来更好的解决方案,并且可能会为您节省大量工作。