Linux下/proc/net/dev中rx_errors和rx_dropped分别统计硬件/驱动层错误与内核协议栈丢弃,字段位置固定(第5列为rx_errors,第13列为rx_dropped),数据为驱动累加的实时计数器,但需注意回绕处理与分层归因。

Linux 下用 /proc/net/dev 读取网卡收发错误与丢包计数
Linux 内核会把每个网络接口的底层统计信息实时写入 /proc/net/dev,包括 rx_errors、tx_errors、rx_dropped、tx_dropped 等关键字段。这不是采样值,而是内核驱动累加的硬件/协议栈级计数器,只要网卡驱动正常上报,数据就是准的。
实操建议:
- 直接用
std::ifstream打开/proc/net/dev,跳过前两行表头,按空格分割每行(注意:第一列是接口名,后面每两个字段为一组:接收、发送,顺序固定) - 第 3 列是
rx_packets,第 4 列是rx_bytes,第 5 列才是rx_errors;第 11 列是tx_errors,第 13 列是rx_dropped,第 15 列是tx_dropped(不同内核版本字段位置一致,但务必用空格+trim 避免 tab 干扰) - 不要依赖
ifconfig或ip -s link的输出——它们是格式化后的摘要,可能隐藏瞬时丢包或驱动未上报的错误类型
Windows 上调用 GetIfEntry2() 获取精确丢包率指标
Windows 的 GetIfEntry2()(需 #include <iphlpapi.h></iphlpapi.h>,链接 iphlpapi.lib)返回的 MIB_IF_ROW2 结构体里,InErrors、OutErrors、InDiscards、OutDiscards 字段对应真实错误与丢包计数,且比旧版 GetIfEntry() 支持更多现代网卡(如 NDIS 6.30+ 的虚拟网卡、SR-IOV VF)。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 调用后
row.InErrors == 0却实际有丢包?检查是否以管理员权限运行——部分驱动(尤其是虚拟化网卡)对非特权进程隐藏错误计数 -
GetIfEntry2()返回ERROR_NOT_FOUND?说明该接口索引已失效,需先用GetIfTable2()刷新接口列表再重试 - 某些 USB 网卡或老式 Realtek 驱动不更新
InDiscards,此时要结合GetPerAdapterInfo()查IP_PER_ADAPTER_INFO中的dwForwarding和dwDefaultTTL辅助判断链路异常
C++ 跨平台轮询时必须处理计数器回绕和采样间隔
网卡计数器是 uint32_t 或 uint64_t 类型,满值后会回绕(wrap-around)。如果两次采样间隔太短(如 100ms),而网卡流量极大,就可能误判为“丢包突增”(其实是回绕后数值变小)。
实操建议:
- 每次读取后与上一次值做差,若差值为负,按无符号类型位宽补全(例如 uint32_t 回绕:差值 = 当前值 + 2^32 − 上次值)
- 最小采样间隔建议 ≥ 500ms;高频监控场景下,优先用
epoll(Linux)或WaitForMultipleObjects(Windows)监听网卡状态变更事件,而非死循环轮询 - 避免在单次采集里混用不同时间戳——
/proc/net/dev是瞬间快照,但读取过程有微秒级延迟;Windows 的MIB_IF_ROW2各字段是原子读取,但跨字段仍可能有微小偏移,应视为同一逻辑时刻
丢包归因不能只看计数器:区分驱动层、协议栈层、应用层丢弃
rx_dropped(Linux)或 InDiscards(Windows)只是总入口丢弃数,背后原因差异极大:可能是 ring buffer 溢出(驱动层)、netfilter 规则 DROP(协议栈层)、socket 接收缓冲区满(应用层)。仅靠一个数字无法定位问题。
可操作的归因路径:
- Linux:检查
/proc/net/snmp中Tcp段的EstabResets和AttemptFails,对比/proc/net/netstat的TcpExt段中SynCookiesSent、ListenOverflows—— 若后者显著升高,说明是 accept 队列溢出导致的丢包 - Windows:用
netsh interface ipv4 show subinterfaces查State是否为connected;再用GetTcpTable2()统计TIME_WAIT连接数,若远超MaxUserPort设置,说明端口耗尽引发连接失败,表现为“伪丢包” - 所有平台:若丢包集中在特定目的 IP/端口,优先抓包验证——
tcpdump -i eth0 'ip dst 192.168.1.100' -w debug.pcap,然后用 Wireshark 看 retransmission 或 dup ACK 模式,比计数器更直观
真正难的是把原始计数映射到具体瓶颈点。驱动日志、dmesg 输出、ETW trace(Windows)这些辅助信号,往往比计数器本身更能说明问题。


















