linux下获取实时出口带宽需读取/proc/net/dev,跳过前两行后提取每行第9列tx_bytes(发送字节数),两次采样求差再除以时间间隔;应仅累加operstatus为up的物理或桥接接口,忽略lo等虚拟接口,使用std::stoull解析防溢出,采样间隔不低于100ms。

Linux下用/proc/net/dev读取实时出口带宽
Linux系统没有“当前出口总带宽使用率”这种现成指标,只有各网卡的收发字节数。所谓“出口带宽趋势”,本质是定期采样/proc/net/dev中tx_bytes字段,做差值再除以时间间隔——这才是真实可用的出口流量速率(单位:B/s)。
关键点:/proc/net/dev每行对应一个网络接口,格式固定,第9列是发送字节数(tx_bytes)。需跳过前两行表头,且只累加处于UP状态的物理/桥接接口(如eth0、enp0s3、br0),忽略lo、docker0等回环或虚拟接口(除非你明确需要它们)。
- 每次读取后sleep 1秒再读第二次,才能算出近似瞬时速率;更平滑的趋势建议用5秒窗口滚动平均
- 注意
stoul()可能抛std::out_of_range,大流量下tx_bytes可能超unsigned long(应改用std::stoull()配unsigned long long) - 文件读取失败时返回-1,不要静默忽略——常见原因是权限不足(非root用户无法读某些容器网络命名空间下的
/proc)
Windows下用GetIfTable2获取每接口发送速率
Windows没有统一的“总出口带宽”概念,必须调用GetIfTable2获取所有活动接口的OutOctets(即发送字节数),再按时间差计算速率。该API从Windows Vista起可用,需链接iphlpapi.lib,且返回结构体中Interface->OutOctets是64位计数器,不会溢出。
容易踩的坑:GetIfTable2返回的接口列表包含大量非活跃或虚拟适配器(如{xxx}-Data、WAN Miniport),直接累加会导致结果虚高。应过滤Interface->OperStatus == IfOperStatusUp且Interface->Type != IF_TYPE_SOFTWARE_LOOPBACK的接口。
- 首次调用后需等待至少500ms再调第二次,否则差值为0(计数器更新有延迟)
- 若程序运行在低完整性级别(如UAC限制下),
GetIfTable2可能返回ERROR_ACCESS_DENIED,此时需提示用户以管理员身份运行 - 别用
GetIfEntry2逐个查——效率低,GetIfTable2一次性拉全量更可靠
C++跨平台封装时别硬算“总带宽百分比”
很多开发者试图用“当前出口速率 / 网卡标称速率”得出百分比,但这是危险操作:ethtool -s eth0 speed返回的是协商速率(如1000),而实际出口受上游链路、QoS策略、TCP拥塞控制影响极大。物理网卡跑不满1Gbps是常态,拿它当分母会严重误导。
真正有意义的是绝对速率趋势(B/s或bps),以及和历史基线的对比。如果非要显示百分比,分母应来自外部配置(如公司宽带合同带宽100Mbps)或上次成功测速结果,而非网卡能力。
- Linux下
ethtool输出的Speed:字段不可靠——虚拟机、bonding、VLAN子接口常报Unknown - Windows下
Interface->Speed字段在无线网卡上常为0,有线网卡也可能因驱动未上报而为0 - 不做任何假设,把“出口速率”定义为纯数值+单位(如
12.4 MiB/s),UI层再决定是否叠加百分比
采样频率与精度的实际取舍
1秒采样能反映突发流量,但噪声大;5秒以上平滑性好,却会掩盖短时毛刺。真实场景中,监控类应用常用双周期:1秒采样存原始数据,后台线程每5秒聚合生成趋势点。
注意std::chrono::steady_clock比system_clock更适合计时——避免NTP校时导致的时间跳变影响差值计算。
- 两次读取间隔必须用
steady_clock::now()相减,不能用sleep_for代替——后者不保证唤醒准时 - Linux下
/proc/net/dev更新频率约100ms,采样间隔低于100ms无意义;Windows下GetIfTable2内核更新周期约200ms - 如果目标是绘制趋势图,建议缓存最近60个点(每5秒1个),足够覆盖1小时,内存占用仅几百字节
"eth0"必然失败,必须每次采样前重新枚举有效接口并匹配逻辑名称(如通过IFLA_IFNAME或Interface->Alias)。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











