Linux下读取/proc/net/dev是最直接可靠的方式,内核暴露网卡收发字节数和包数,数据为累计值、更新频率约100ms、无需root权限;需跳过前两行表头,每行17列,rx_bytes在第2列、tx_bytes在第10列(索引从0起),用std::istringstream配合std::skipws鲁棒解析,两次采样求差除以时间间隔得B/s速率。

Linux下读取/proc/net/dev是最直接可靠的方式
Linux内核通过/proc/net/dev暴露网卡收发字节数和包数,数据是累计值、非实时差值,但精度足够(更新频率约100ms),且无需root权限。注意字段顺序固定但首两行是表头,需跳过;每行包含17个字段,rx_bytes在第2列、tx_bytes在第10列(从0开始计)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
std::ifstream打开/proc/net/dev,逐行读取,用std::istringstream按空格分割,跳过前两行 - 对目标网卡(如
eth0或wlan0)匹配行首字符串,避免误匹配别名(如eth0:1) - 提取第2列和第10列的
unsigned long long数值,两次采样后相减再除以时间间隔,即得B/s速率 - 注意字段可能被空格/制表符混合分隔,用
std::skipws或循环>>更鲁棒
Windows下必须调用GetIfEntry2或GetIfTable2
Windows没有类似/proc的伪文件系统,旧API如GetIfTable已废弃,必须用支持IPv6和高精度计数器的GetIfEntry2(推荐)或GetIfTable2。它们返回MIB_IF_ROW2结构,其中InOctets和OutOctets字段即为累计收发字节数。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 需链接
iphlpapi.lib,并定义WIN32_LEAN_AND_MEAN防止宏冲突 - 先调用
GetIfEntry2获取单个接口(需已知LUID),或用GetIfTable2遍历所有接口再按InterfaceDescription或Alias筛选 -
MIB_IF_ROW2中InterfaceLuid比InterfaceIndex更稳定(后者可能随重启变化) - 若返回
ERROR_NOT_FOUND,说明接口未启用或驱动不支持——某些虚拟网卡(如Docker、WSL2虚拟适配器)可能不报告流量
跨平台封装要注意计数器溢出和采样时机
无论Linux还是Windows,底层计数器都是无符号64位整数,理论上不会溢出(按10Gbps满载也要约600年),但两次采样间隔不能太长(如>1小时),否则差值可能因系统休眠、网卡重置等异常归零,导致计算出极大负值或错误峰值。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 每次采样后保存上一次的
rx_bytes/tx_bytes和对应std::chrono::steady_clock::now()时间戳 - 若本次读取值小于上次(说明计数器重置),应丢弃该次差值,沿用历史速率或标记为“不可用”
- 最小采样间隔建议≥200ms:太短则噪声大,太长则无法反映突发流量;可用
std::this_thread::sleep_for控制节奏 - 避免在信号处理函数或高频定时器中直接读取——
/proc/net/dev是同步IO,Windows API有临界区,频繁调用可能阻塞
不要用libpcap或抓包方式统计实时流量
有人想用libpcap监听所有包再累加长度,这完全偏离目标:它只捕获本机协议栈交付给应用层的包(不包括转发、ICMP响应、内核丢弃包),且开启混杂模式需要管理员权限,CPU开销高,还受缓冲区丢失影响。真实网络设备级流量必须走内核暴露的统计接口。
典型错误现象:
- 测得流量始终为0:未设置
pcap_set_promisc或权限不足 - 数值明显偏低(如只有预期50%):过滤规则漏掉ARP、广播包,或TCP分段未重组
- 程序CPU占用率飙升到100%:
pcap_loop未设超时,持续轮询 - 与
/proc/net/dev结果相差2–3倍:抓包路径在netfilter之后,而内核统计在驱动入口处
真正需要包级分析时再用libpcap,流量监控场景下它只是个高成本、低精度、难维护的替代方案。


















