Windows无直接丢包率API,需用ICMP Ping滑动窗口计算成功率或ETW获取TCP重传率;dwInErrors等字段反映驱动层故障而非网络丢包。

Windows 上没有直接返回“丢包率”的系统 API,GetIfEntry2 和 GetIfTable2 只提供原始收发包计数和错误计数,丢包率必须你自己算,而且得连续采样——单次读数毫无意义。
为什么 GetIfEntry2 返回的 dwInErrors/dwOutErrors 不能直接当丢包率用
这两个字段统计的是底层驱动上报的“不可恢复错误”,比如 DMA 失败、校验和硬件检测失败、缓冲区溢出等,不是 ICMP 超时或 TCP 重传失败。它们和你 ping 看到的“10% 丢包”完全不是一回事。真实网络丢包(如路由黑洞、ACL 拦截、中间设备限速)根本不会增加这些计数。
常见误用现象:dwInErrors / (dwInUcastPkts + dwInNUcastPkts) 算出来长期是 0.001%,但实际业务连接频繁超时。
- 它反映的是网卡/驱动层故障,不是链路质量
- 多数现代网卡在无异常时该值恒为 0,哪怕物理链路已断
- Linux 的
/proc/net/dev同理,errs列也不等于丢包
用 ICMP Ping + 时间窗口做近似丢包率(最实用方案)
这是监控工具(如 Zabbix、Prometheus + node_exporter)真正采用的方式:起一个后台线程,每秒向网关或 DNS 服务器发 1 个 ICMP 包,记录应答延迟和是否超时,滑动窗口维护最近 60 秒数据,实时计算成功率。
立即学习“C++免费学习笔记(深入)”;
关键实操点:
- 目标选本地网关(
GetIpForwardTable2查NextHop),别用公网地址——避免引入外网抖动干扰本机链路判断 - 用
IcmpSendEcho2(非过时的IcmpSendEcho),支持异步、可设超时(建议 500ms)、能捕获IP_STATUS_TIMED_OUT - 不要用
system("ping"):启动开销大、解析输出不稳定、无法控制并发和超时精度 - 滑动窗口用
std::deque<bool></bool>存成功/失败标记,比算总数再除更准(避免整数除零或精度丢失)
示例逻辑片段:
BOOL success = IcmpSendEcho2(hIcmp, NULL, NULL, NULL,
&destAddr, sendBuf, sizeof(sendBuf), &opt, replyBuf, replySize, 500);
从 ETW 获取 TCP 重传统计(进阶:关联应用层丢包)
如果想定位“为什么 HTTP 请求慢”,光看 ICMP 不够——TCP 层重传才是更贴近业务的指标。Windows 有内置 ETW provider:Microsoft-Windows-TCPIP,事件 ID 10(TcpSendData)和 11(TcpRetransmit)可被消费。
实操门槛较高,但值得投入:
- 需以管理员权限运行,否则
StartTrace失败并报错ERROR_ACCESS_DENIED - 事件中
RetransmitCount字段是累计值,必须两次采样相减,不能直接用 - 过滤目标进程 PID 需在
ENABLE_TRACE_PARAMETERS中设MatchAnyKeyword和EnableProperty,漏掉就收不到 - 性能影响小(内核态采集),但解析 ETW 事件要用
TraceEvent库或自己解析二进制 payload
注意:TcpRetransmit 事件只在重传真正发生时触发,比 Wireshark 抓包轻量,但比 ICMP 方案延迟高(通常秒级聚合)。
真正难的不是读哪个字段,而是理解“丢包率”本身是个上下文强依赖的概念:对运维是 ICMP 连通性,对 SRE 是 TCP 重传率,对驱动开发才是 dwOutErrors。选错指标,监控就变成自欺欺人。


















