直接读取/proc/net/dev可获取网卡实时流量,需跳过前两行表头,按空格分割提取非空token,取第1个(rx_bytes)和第9个(tx_bytes)字段,校验size≥9后转换为uint64_t,两次采样求差值除以时间间隔得速率。

Linux 下用 /proc/net/dev 解析网卡流量差值
直接读取 /proc/net/dev 是最轻量、无依赖的方式。它每秒提供各网卡的累计字节数(rx_bytes 和 tx_bytes),速度就是两次采样之差除以时间间隔。
注意点:
- 文件中前两行是表头,需跳过;每行格式为
ens3: 123456789 ... 987654321,冒号后第一个数字是接收字节,第九个是发送字节(按空格分割后索引为 1 和 9) - 必须用同一网卡设备名(如
eth0、wlan0或ens33),不能硬编码,建议先从/proc/net/dev中过滤出活跃且非 loopback 的接口 - 数值是无符号 64 位整数,溢出极罕见,但要用
uint64_t接收,避免符号扩展错误 - 两次读取间隔建议 ≥ 500ms,太短会导致抖动大,
std::this_thread::sleep_for控制即可
// 示例:提取 ens3 的 rx/tx 字节数(伪代码逻辑)
std::ifstream dev{"/proc/net/dev"};
std::string line;
while (std::getline(dev, line)) {
if (line.find("ens3:") != std::string::npos) {
std::istringstream iss(line.substr(line.find(':') + 1));
uint64_t rx_bytes, tx_bytes;
iss >> rx_bytes; // 跳过 7 个字段再读第 9 个得 tx
for (int i = 0; i > std::ws;
iss >> tx_bytes;
}
}
Windows 下调用 GetIfTable2 获取实时速率
Windows 没有类似 /proc 的文本接口,必须用 IP Helper API。推荐 GetIfTable2(而非已废弃的 GetIfTable),它返回 MIB_IF_ROW2 结构,含 InOctets 和 OutOctets 字段。
关键细节:
- 需链接
iphlpapi.lib,头文件为<iphlpapi.h></iphlpapi.h> - 接口索引(
InterfaceIndex)比名称更可靠,先用GetIfEntry2或遍历GetIfTable2结果匹配名称(如L"Ethernet")获取索引 - 两次调用间必须用
GetTickCount64()计算毫秒差,不能用std::chrono高精度时钟——因为InOctets更新频率由系统驱动决定,通常为秒级,高频读取无意义 - 返回值为
NO_ERROR才有效,ERROR_NO_DATA表示接口未启用或无流量
跨平台封装要注意的三个兼容性坑
如果想写一次逻辑跑两边,别直接封装成“获取速度函数”,而应分层:采集层(OS-specific)、差分层(通用)、单位转换层(可选)。
常见翻车点:
-
/proc/net/dev的字段顺序在不同内核版本稳定,但 Windows 的MIB_IF_ROW2在 Win7+ 可用,WinXP 不支持,若需兼容旧系统,得回退到GetIfTable+MIB_IFROW(仅提供总包数,无字节数) - Linux 网卡名可能动态变化(如
enp0s3→ens33),建议按 MAC 地址匹配,而非名称字符串 - 上传/下载方向容易反:Linux 的
rx_bytes是本机收到的数据(即下载),tx_bytes是发出的(上传);Windows 的InOctets同理对应下载,别按字面“in/out”直译
为什么不用 libpcap 或 netstat 命令解析
这两种方案看似简单,实际不适用于持续测速场景。
原因很实在:
-
libpcap抓包是镜像复制,开销大、丢包率随流量上升,且默认只捕获本机收发的包(不包括转发),无法反映真实网卡吞吐;它适合分析协议,不适合计量速率 - 调用
netstat -i或ip -s link再 parse 输出,本质是 shell 调用 + 文本解析,启动慢、不稳定、易被输出格式变更破坏(比如 locale 改变导致千位分隔符出现) - 两者都无法提供亚秒级精度,而
/proc/net/dev和GetIfTable2是内核内存直读,延迟在微秒级
真要监控,就绕过中间层,直取源头数据。差值计算本身很简单,难的是选对源头和稳住采样节奏。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











