bigywater.tech
网络协议 · 14

ICMP echo:ping 的往返时间从哪里来

ping 一次到底发了什么?RTT 是从哪里量出来的?-s 改了载荷大小以后线上有什么变化?这篇在 lo0 和 en0 上抓 ICMP echo 的请求与应答,手算校验和,对比 ping 报的时间和抓包的时间,再用不需要 root 的 ICMP 套接字自己发一个 echo。

84 字节
ping 默认的 IP 包大小:20 字节 IP 头 + 8 字节 ICMP 头 + 56 字节载荷
0.084~0.534 ms
ping 报告的 RTT 比抓包里请求到应答的时间差多出的部分(30 个逐个对比)
4000 → 90 个包
载荷 4000 字节的 15 个 ping,请求和应答各分成 3 片

echo 请求与应答

实测 · 本机执行输出
  127.0.0.1(lo0):抓到 2 个包
    请求:IP 总长 84,TTL 64,IP 头里的标识 65089,ICMP 类型 8 代码 0,标识符 0x441a,序号 0,载荷 56 字节
    应答:IP 总长 84,TTL 64,IP 头里的标识 7578,ICMP 类型 0 代码 0,标识符 0x441a,序号 0,载荷 56 字节
    请求的载荷前 8 字节是发送时间:秒 1792027662、微秒 468410;与抓包时间戳相差 25 µs;后 48 字节是 0x08 起逐字节加 1 的图案(确认递增)
    应答的标识符、序号、载荷与请求完全相同:True;IP 头 + ICMP 头 + 载荷 = 20 + 8 + 56 = 84 字节
  默认网关(en0):抓到 2 个包
    请求:IP 总长 84,TTL 64,IP 头里的标识 40976,ICMP 类型 8 代码 0,标识符 0x481a,序号 0,载荷 56 字节
    应答:IP 总长 84,TTL 64,IP 头里的标识 14738,ICMP 类型 0 代码 0,标识符 0x481a,序号 0,载荷 56 字节
    请求的载荷前 8 字节是发送时间:秒 1792027663、微秒 128071;与抓包时间戳相差 215 µs;后 48 字节是 0x08 起逐字节加 1 的图案(确认递增)
    应答的标识符、序号、载荷与请求完全相同:True;IP 头 + ICMP 头 + 载荷 = 20 + 8 + 56 = 84 字节

类型 8 是请求、0 是应答,代码都是 0;标识符、序号、载荷在应答里原样回送。ping 把发送时间放在载荷前 8 字节里,收到应答后直接取出来算 RTT。

校验和

实测 · 本机执行输出
  lo0 请求:抓到的校验和 0x618a,自己算的 0x618a,一致;把整个 ICMP 报文(含校验和)再求和得 0x0000
  lo0 应答:抓到的校验和 0x698a,自己算的 0x698a,一致;把整个 ICMP 报文(含校验和)再求和得 0x0000
  en0 请求:抓到的校验和 0x1070,自己算的 0x1070,一致;把整个 ICMP 报文(含校验和)再求和得 0x0000
  en0 应答:抓到的校验和 0x1870,自己算的 0x1870,一致;把整个 ICMP 报文(含校验和)再求和得 0x0000
  规则:校验和字段先填 0,对整个 ICMP 报文(头 + 载荷,不含 IP 头)按 16 位字求和、进位折回、取反;收到的人对整个报文求和,结果应该是 0

只覆盖 ICMP 报文,不含 IP 头。自己算的值和 lo0、en0 上四个包完全一致;含校验和再求一次和等于 0。

RTT

实测 · 本机执行输出
  默认网关:发 30 个,收到应答 30 个;ping 报告的 RTT 最小 2.613 / 中位 2.958 / 最大 35.607 ms
  抓包得到的 RTT(请求到应答之间的时间差)最小 2.364 / 中位 2.751 / 最大 35.458 ms
  逐个对比 30 个:ping 报的比抓包多 0.084~0.534 ms(中位 0.194)——ping 从发出前到应答被读到,比网卡上看到的多一段
  最慢的 3 个 RTT: [25.177, 29.527, 35.607];最快的 3 个: [2.613, 2.638, 2.658]
  127.0.0.1:收到 30 个;ping 报告 最小 0.074 / 中位 0.132 / 最大 0.290 ms;抓包 RTT 中位 0.043 ms
  网关的 RTT 中位是 127.0.0.1 的 22 倍(Wi-Fi 链路上一来一回 + 网关处理)

局域网网关的 RTT 中位约 3 ms,127.0.0.1 约 0.13 ms。ping 报告的时间总比抓包多一点本机内部的耗时;Wi-Fi 上偶尔出现几十毫秒的尖峰。

载荷大小

实测 · 本机执行输出
  载荷    0 字节:第一个包 IP 总长 28;收到 15/15,ping 打印出 time= 的有 0 个;抓包 RTT 最小 2.348 / 中位 4.087 ms;抓到 30 个 IP 包,其中是分片的(MF 置位或偏移非 0)有 0 个
  载荷   56 字节:第一个包 IP 总长 84;收到 15/15,ping 打印出 time= 的有 15 个;抓包 RTT 最小 2.256 / 中位 3.623 ms;抓到 30 个 IP 包,其中是分片的(MF 置位或偏移非 0)有 0 个
  载荷  512 字节:第一个包 IP 总长 540;收到 15/15,ping 打印出 time= 的有 15 个;抓包 RTT 最小 2.397 / 中位 2.850 ms;抓到 30 个 IP 包,其中是分片的(MF 置位或偏移非 0)有 0 个
  载荷 1472 字节:第一个包 IP 总长 1500;收到 15/15,ping 打印出 time= 的有 15 个;抓包 RTT 最小 2.496 / 中位 2.867 ms;抓到 30 个 IP 包,其中是分片的(MF 置位或偏移非 0)有 0 个
  载荷 4000 字节:第一个包 IP 总长 1500;收到 15/15,ping 打印出 time= 的有 15 个;抓包 RTT 最小 2.963 / 中位 3.395 ms;抓到 90 个 IP 包,其中是分片的(MF 置位或偏移非 0)有 90 个
  载荷 0 → 4000 字节,抓包 RTT 中位的变化: 4.087 → 3.623 → 2.850 → 2.867 → 3.395 ms

载荷小于 8 字节放不下时间戳,ping 不显示 time。载荷超过 MTU 时请求和应答都会分片。15 个样本的实验里 RTT 受抖动影响比受大小影响大。

非特权 ICMP 套接字

实测 · 本机执行输出
  我填的:类型 8 代码 0 标识符 0x1234 序号 7 载荷 34 字节
  线上发出的请求:标识符 0x1234 序号 7 载荷 34 字节;载荷与我填的相同:True;标识符保持了
  线上收到的应答:标识符 0x1234 序号 7 载荷相同:True
  recvfrom 拿到 62 字节:开头是 IP 头(版本/IHL=0x45,头长 20),后面是 ICMP 类型 0 代码 0;应用层测得 RTT 3.269 ms
  应用里收到的 ICMP 标识符 0x1234(线上是 0x1234)
  同时开着另一个 ICMP 套接字 s2(自己从没发过包),s 又发了一次请求:s2 收到了一个 62 字节的包(ICMP 类型 0,标识符 0x1234,序号 7)——也就是说在这台机器上,ICMP 数据报套接字并不只收自己发出的请求的应答(这里只观察到现象,没有进一步验证内核的分发规则)

macOS 允许普通用户用 SOCK_DGRAM + IPPROTO_ICMP 发 echo,标识符、序号和载荷原样上线;recvfrom 收到的数据带 IP 头。

分步演示

ICMP echo
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64(Apple 芯片)/ Python 3.14.8 / tcpdump(libpcap)/ scapy 2.8 / dpkt / dnspython / h2 / aioquic / OpenSSL / curl 8.7.1;抓包在 lo0(环回)上做,少数实验用真实网卡 en0(这台机器上 en0 是 Wi-Fi,tcpdump 看到的是系统转成以太网格式的帧,所以文中的“以太网头”都指这个 14 字节的头)或访问公网(会在文章里注明);需要丢包 / 延迟 / 限速时,用一个只作用于 lo0 端口 9400-9499 的 dummynet 辅助脚本(netlab);所有服务端都是本机自己起的进程;时间戳取自 tcpdump 的 -tt,数字每次运行会有小幅抖动。第一、二、五节在 lo0 与 en0 上抓包(用 dpkt 解析),默认网关地址与 MAC 做了遮盖;第三、四节 ping 间隔 0.2 s,网关是同一 Wi-Fi 网络里的路由器,RTT 数字随当时的无线环境变化,只看量级与相对关系
    • 没有验证:ICMP 其它类型(时间戳 13/14、地址掩码请求等,见后面的差错报文一篇);内核如何把应答分发给不同 ICMP 套接字;ping 以外工具(如 fping)的计时方式;更大样本下载荷大小与 RTT 的定量关系;公网 ICMP echo(本机的网络挡住了对外的 ping)
    京ICP备2026067502号-1京公网安备11010502063487号