IP 地址要变成 MAC 才能发出帧,这一步靠 ARP。邻居表里存着什么、请求和应答在线上长什么样、没人应答时会怎样重试、网段里每分钟有多少 ARP 在跑?这篇用 tcpdump 抓真实网段,并看 macOS 的邻居表。
arp -an 在 en0 上有 81 条已解析的邻居(同一个网段里的设备) ? (<本机局域网IP>) at 70:85:6c:xx:xx:xx on en0 ifscope [ethernet] netstat -rn 里网关 <本机局域网IP> 的主机路由:标志 UHLWIir(U 可用 H 主机路由 L 链路层地址 W 由 ARP 自动生成 I 接口作用域 R 拒绝 i 地址完成),Expire 剩余 1180 秒 系统参数: max_age=1200, maxtries=5, host_down_time=20 5 秒之后 Expire 剩余 1199 秒(倒计时;每次用到这条邻居时系统会刷新 / 到期后重新发 ARP 请求确认)
每条记录是 IP → MAC,带寿命(macOS 的 max_age 是 1200 秒);netstat -rn 里 ARP 学来的条目标志含 W 和 L。
+ 0.000 ms 请求 帧长 42 以太网: 目的 ff:ff:ff:xx:xx:xx(广播) 源 7e:aa:6f:xx:xx:xx 类型 0x0806
ARP: 硬件类型 1(1=以太网) 协议类型 0x0800(IPv4) 硬件地址长 6 协议地址长 4 操作 1(请求 who-has)
发送方 MAC 7e:aa:6f:xx:xx:xx IP <本机局域网IP>;目标 MAC 00:00:00:00:00:00(未知) IP <本机局域网IP>
+ 93.529 ms 应答 帧长 60 以太网: 目的 7e:aa:6f:xx:xx:xx(单播) 源 a6:a0:d9:xx:xx:xx 类型 0x0806
ARP: 硬件类型 1(1=以太网) 协议类型 0x0800(IPv4) 硬件地址长 6 协议地址长 4 操作 2(应答 is-at)
发送方 MAC a6:a0:d9:xx:xx:xx IP <本机局域网IP>;目标 MAC 7e:aa:6f:xx:xx:xx IP <本机局域网IP>
请求到应答 93.53 ms(解析一个邻居的代价);之后 ping 才真正发出。ARP 报文本体 28 字节
这台主机的 MAC 现在在本机缓存里: True请求是广播帧,目标 MAC 全 0;应答是单播,带上对方的 MAC。ARP 报文本体 28 字节,放在 14 字节的以太网头后面。
本机发出的 ARP 请求 5 个,时刻(相对第一个,秒): [0.0, 1.01, 2.01, 3.01, 4.02] ping 的输出: PING <本机局域网IP> (<本机局域网IP>): 56 data bytes | Request timeout for icmp_seq 0 | Request timeout for icmp_seq 1 | Request timeout for icmp_seq 2 | Request timeout for icmp_seq 3 | Request timeout for icmp_seq 4 | Request timeout for icmp_seq 5 | Request timeout for icmp_seq 6 | --- <本机局域网IP> arp -an 里这个地址的状态: ? (<本机局域网IP>) at (incomplete) on en0 ifscope [ethernet] ← incomplete = 已发了请求、一直没等到应答
内核每秒重发一次请求,最多 maxtries=5 次,条目停在 (incomplete);再往这个地址发包会立刻失败。
30 秒共 168 个 ARP 帧:请求 166 个(广播)、应答 2 个(单播);其中免费 ARP(发送方 IP = 目标 IP)12 个,ARP 探测(发送方 IP = 0.0.0.0)7 个 配上对的请求 → 应答 2 对,延迟 p50 0.09 ms,p90 0.09 ms,最大 0.09 ms 应答只抓到极少数:应答是单播,通常只送到提问者,本机这个抓包点看不到别人收到的单播;而请求是广播,整个网段都能看到(请求 166 个对应答 2 个就是这个原因)
广播的请求整个网段都听得到;免费 ARP 和探测用于宣告 / 检测地址冲突。
en0 上与本机地址 <本机局域网IP> 相关的 ARP 帧:0 个;lo0 上非 IP 的帧(ARP 或别的):0 个——发往本机自己的地址走本机内部(lo0),根本不会出网卡,也就不需要 ARP
发给本机自己的地址走 lo0,不会出网卡,也就没有 ARP。