Windows/Linux均无直接获取丢包率的API,需通过ICMP ping滑动窗口统计(超时数/总请求数)、SNMP/TCP重传字段或ethtool/WMI驱动层错误计数等多源计算,且各指标含义不同。

Windows 上没有现成的 API 能直接获取「网络适配器丢包率」——它不是操作系统暴露的实时指标,而是需要你自己算出来的。 Linux 同理。所谓“丢包率”,本质是基于发送/接收计数差值和重传行为推导的估算值,不同场景(TCP vs ICMP vs UDP)含义完全不同。别被某些监控工具的“丢包率 2.3%”误导,那背后可能是 ping 统计、SNMP 查询,或驱动层私有 IOCTL,绝非内核直出字段。
为什么 GetIfEntry2 / GetIpStatisticsEx 拿不到丢包率
Windows 的 GetIfEntry2 返回的 MIB_IF_ROW2 结构里有 OutDiscards、InDiscards、OutErrors 等字段,但这些是协议栈丢弃计数(比如缓冲区满、校验失败),不等于「传输层感知的丢包」;GetIpStatisticsEx 的 dwForwarding 或 dwDefaultTTL 更是完全无关项。真实丢包(例如 TCP 重传触发、ICMP 目标不可达)必须靠主动探测或驱动级 hook 才能捕获。
-
OutDiscards常为 0,除非网卡驱动或 NDIS 层明确上报丢弃(多数不报) -
dwNumOutNdiscards(IPv6 统计)同理,非丢包率,是 ND 协议处理失败次数 - 所有这些字段都是累计值,需两次采样做 delta 计算,且单位是「个数」,不是百分比
用 ICMP ping + 时间窗口统计最实用(Windows/Linux 通吃)
这是工程中最可控、用户最能理解的方式:起一个后台线程,对网关或 DNS(如 8.8.8.8)持续发 ICMP Echo Request,记录发出时间、收到时间、超时事件,滑动窗口(如 60 秒)内计算「超时数 / 总请求数」。注意别用 system("ping"),要调用原始套接字或平台 API:
- Windows:用
IcmpSendEcho2+OVERLAPPED实现异步批量 ping,避免阻塞 - Linux:用
sendto/recvfrom操作AF_INET+SOCK_RAW(需 root),或更稳妥地调liboping - 每秒最多发 1–2 个包,高频 ping 易被防火墙限速或判定为扫描
- 丢包率 =
(timeout_count / total_sent),不是(timeout_count / total_received)
Linux 下读取 /proc/net/snmp 要小心字段偏移
很多人查到 /proc/net/snmp 里有 Ip: InDiscards OutDiscards,但这是 IPv4 MIB 统计,且字段顺序固定但版本依赖强。例如 RHEL 7 和 Ubuntu 22.04 的 Tcp: 行中 RetransSegs 位置可能差一列。正确做法是先解析 header 行:
Ip: Forwarding DefaultTTL InReceives InHdrErrors ... OutDiscards
再按列名索引数值,而非硬编码下标。另外:InDiscards 不代表链路丢包,可能是本地 socket 接收队列溢出(net.core.rmem_default 太小);Tcp: RetransSegs 才更贴近“因丢包导致的重传”,但它混入了乱序重传、定时器误触发等情况。
别忽略 NIC 驱动层真实丢包(ethtool / WMI)
真正影响用户体验的丢包,常发生在网卡 DMA 或 Ring Buffer 溢出时,这类数据 Windows 要通过 WMI 查询 MS_NetworkAdapterPerformance 类的 ReceiveError、TransmitError,Linux 则用 ethtool -S eth0 看 rx_missed_errors、tx_aborted_errors。这些才是物理层/驱动层丢包,但它们是累计值、无时间粒度,且部分网卡驱动不实现该统计。
- Windows WMI 查询慢,建议缓存 5 秒以上再刷新,别每秒轮询
-
ethtool -S输出字段名不统一:Intel 卡叫rx_discards,Mellanox 叫rx_out_of_buffer - 这类错误一旦出现,往往已伴随
netstat -s中大量packet receive errors,说明问题严重
丢包率从来不是一个单一数字,它是三层上下文叠加的结果:ICMP 探测反映端到端路径质量,SNMP/TCP 统计反映协议栈行为,ethtool/WMI 数据反映硬件承载能力。监控时务必标注来源,否则看到“丢包率 5%”却不知道是 ping 超时、TCP 重传还是 rx_ring 溢出,就等于没监控。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











