用system()调用ping命令简单但不可靠,存在跨平台差、输出不统一、无法实时捕获延迟等问题;推荐使用libtins等成熟库封装ICMP实现跨平台低延迟ping检测。

直接用 system() 调用 ping 命令最简单,但不可靠
多数人第一反应是用 system("ping -c 1 google.com") 拿输出,但这有硬伤:依赖 shell、跨平台差(Windows 用 ping -n 1)、输出格式不统一、无法实时捕获延迟值。更麻烦的是,system() 阻塞主线程,且返回值只是退出码,不是延迟本身。
- Linux 下
ping输出里延迟在time=XX.X ms这一行;Windows 是时间 = XXms,正则匹配要分平台 - 超时或丢包时,
ping仍可能返回 0(比如发包成功但没收到回包),不能单靠system()返回值判断是否成功 - 频繁调用会起一堆子进程,开销大,不适合高频监控(如每秒测一次)
用原始 socket 发 ICMP 包才是真“实时”,但得自己构造报文
C++ 标准库不提供 ICMP 接口,必须用系统 API:sendto()/recvfrom() 配合 AF_INET + SOCK_RAW。Linux 需 root 权限,Windows 需启用 IP_HDRINCL 并处理协议栈差异。
- ICMP 报文结构固定:8 字节头部(类型、代码、校验和、标识符、序列号)+ 可选数据(常用 56 字节)
- 发送前必须手动计算 ICMP 校验和——漏掉这步,目标主机直接丢包,
recvfrom()永远等不到响应 - Windows 上
WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, ...)必须传WSA_FLAG_MULTIPOINT_CLENT才能收 ICMP 回包,否则静默失败
std::chrono 记时必须配 clock_gettime(CLOCK_MONOTONIC) 或高精度计时器
用 std::chrono::steady_clock::now() 测发送到接收的时间差,看似合理,但实际误差可能达 10–20ms(尤其在负载高的机器上)。真正低延迟场景(如游戏服务器心跳检测)需绕过 C++ 标准时钟。
- Linux 推荐
clock_gettime(CLOCK_MONOTONIC, &ts),纳秒级精度,不受系统时间调整影响 - Windows 用
QueryPerformanceCounter()+QueryPerformanceFrequency(),比GetTickCount64()精确一个数量级 - 别用
std::time(nullptr)或std::chrono::system_clock——它们反映的是墙上时间,可能被 NTP 向后跳变,导致延迟算出负值
推荐方案:用 libpcap 或 libtins 封装 ICMP,省去权限和协议细节
自己手撸 ICMP 太重,生产环境建议用成熟网络库。例如 libtins(C++11,跨平台)封装了完整 ICMPv4/v6 ping,内部已处理权限提升、校验和、超时重试和时间戳对齐。
立即学习“C++免费学习笔记(深入)”;
- Linux 下安装后加
-ltins链接,代码只需几行:Tins::ICMP::Ping ping("8.8.8.8"); auto result = ping.ping(); if (result.success()) { std::cout - Windows 需先安装 WinPcap/Npcap,
libtins会自动调用其驱动抓包,绕过 raw socket 权限限制 - 注意
libtins默认用std::chrono::steady_clock,若需更高精度,可传入自定义时钟对象
真正难的不是“怎么测”,而是“测出来的数到底代表什么”——ICMP 延迟受路由策略、防火墙限速、中间设备 QoS 影响极大,同一台机器 ping 不同域名,延迟可能差 50ms 以上。别把它当 TCP RTT 用,也别拿它直接调优应用层超时逻辑。


















