系列说明:《从 TCP/IP 到 AI 智算网络》每一步都让你动手做一遍。全程 VMware + Ubuntu,不需要专用硬件。
本篇定位:第一部分「TCP/IP 传统协议栈」第 02 篇。讲完最底层的以太网帧(第 01 篇),你自然要问:以太网只认 MAC 地址,那我知道对方 IP 地址,怎么拿到它的 MAC?这就是 ARP 干的事。
一、这个协议有什么用
ARP 全称
ARP = Address Resolution Protocol(地址解析协议)。
为什么需要 ARP?
回忆第 01 篇的比喻:以太网帧是"快递纸箱",纸箱上必须写收件人 MAC 地址(身份证号),快递员(交换机)才认。
但问题是------你在电脑上配的是 IP 地址(工号),应用程序也只知道对方的 IP。比如你敲:
bash
ping 192.168.95.130
系统只知道"我要找 192.168.95.130",但以太网纸箱上不能写 IP,必须写 MAC。
ARP 就是那个"把 IP 翻译成 MAC"的翻译官。
打个比方:
|-----------------------------------|---------------------|
| 场景 | 网络对应 |
| 你知道同事的工号(IP),但不知道他坐哪 | 系统知道目标 IP,不知道目标 MAC |
| 你在楼道里喊一嗓子:"工号 130 的同事,报一下你的座位号!" | ARP 广播请求 |
| 那个同事举手回答:"我是 130,我坐 A 排 3 号(MAC)" | ARP 单播应答 |
| 你记在脑子里,下次直接走过去 | 系统把 MAC 存入 ARP 缓存表 |
一句话总结:ARP 解决的是"我知道你 IP,但以太网要 MAC,怎么办"的问题。没有 ARP,局域网里任何两台机器都"说不上一句话"。
二、ARP 协议原理和交互过程
1. ARP 怎么工作(四步走)
纯文本
步骤 1:查缓存 → 系统先翻"小本本"(ARP 表),看之前记没记过
│
├─ 记过 → 直接用,跳过 ARP(你上次抓包"先 ICMP 后 ARP"就是这个原因)
│
└─ 没记过 → 进入步骤 2
│
步骤 2:广播喊话 → 发 ARP 请求(目的 MAC = ff:ff:ff:ff:ff:ff,全楼广播)
│
步骤 3:目标回答 → 只有 IP 匹配的机器回 ARP 应答(单播,只告诉你)
│
步骤 4:记小本本 → 系统把"IP ↔ MAC"存进 ARP 缓存,以后直接用
2. ARP 报文长什么样
ARP 报文直接装在 Ethernet II 帧的数据部分(不经过 IP 层!),EtherType = 0x0806。
|------------------|------------|------------------------------------------|
| 字段 | 长度 | 说明 |
| 硬件类型 | 2 字节 | 固定 0x0001(以太网) |
| 协议类型 | 2 字节 | 0x0800(要解析的是 IPv4) |
| 硬件地址长度 | 1 字节 | 6(MAC 地址 6 字节) |
| 协议地址长度 | 1 字节 | 4(IPv4 地址 4 字节) |
| **操作码(Opcode)** | 2 字节 | **1 = 请求(Request),2 = 应答(Reply)** |
| 发送方 MAC | 6 字节 | 谁在问 / 谁在答 |
| 发送方 IP | 4 字节 | 谁在问 / 谁在答 |
| 目标 MAC | 6 字节 | 请求时填 00:00:00:00:00:00(还不知道),应答时填对方的 MAC |
| 目标 IP | 4 字节 | 要查谁的 MAC |
3. 请求 vs 应答对照
|----------------|----------------------------|---------------------|
| | ARP 请求 | ARP 应答 |
| 以太网目的 MAC | ff:ff:ff:ff:ff:ff(广播,所有人收) | 请求者的 MAC(单播,只给提问的人) |
| 操作码 | 1(Request) | 2(Reply) |
| 目标 MAC 字段 | 00:00:00:00:00:00(不知道) | 填请求者的 MAC |
| 谁发 | 想知道 MAC 的那台机器 | 被问到的那台机器 |
三、VMware 环境实测
1. 实验拓扑
和上一篇一样,VMnet1 自定义 LAN 段(192.168.95.0/24),两台 Ubuntu 虚拟机直连:
|------------|----------------|-------------------|-------------|
| 主机 | IP | MAC | 备注 |
| Host A | 192.168.95.128 | 00:0c:29:48:5d:fa | 发起 ping 的一方 |
| Host B | 192.168.95.130 | 00:50:56:37:cb:08 | 被 ping 的一方 |
2. 实验步骤(重点:先清缓存!)
**为什么要清缓存?** 因为 Linux 会记住之前解析过的 MAC(缓存),如果不清,系统直接查表就用,你抓不到 ARP 广播过程。清掉缓存,才能看到"从零开始翻译"的完整流程。
终端 1(Host A 上,清缓存):
bash
先看看当前 ARP 表
arp -n# 或
ip neigh show
清空 ARP 缓存sudo ip neigh flush dev ens33
确认已清空
arp -n# 此时应该看不到 192.168.95.130 的条目

终端 2(Host A 上,开 Wireshark 抓包):
打开 Wireshark,选择 ens33 接口,设置过滤条件:
纯文本
arp || icmp
这样只显示 ARP 和 ICMP 报文,排除 NTP、DNS、IPv6 等干扰。
终端 1(Host A 上,触发流量):
bash
ping -c 1 192.168.95.130

3. 抓包结果解读
清完缓存后 ping 一次,Wireshark 里你会看到类似这样的报文序列:
|-------------|------------|----------------|----------------|---------------------------------------------|
| No. | 协议 | 源 | 目的 | 信息 |
| 1 | ARP | 192.168.95.128 | Broadcast | Who has 192.168.95.130? Tell 192.168.95.128 |
| 2 | ARP | 192.168.95.130 | 192.168.95.128 | 192.168.95.130 is at 00:50:56:37:cb:08 |
| 3 | ICMP | 192.168.95.128 | 192.168.95.130 | Echo request |
| 4 | ICMP | 192.168.95.130 | 192.168.95.128 | Echo reply |
| 5 | ARP | 192.168.95.130 | Broadcast | Who has 192.168.95.128? Tell 192.168.95.130 |
| 6 | ARP | 192.168.95.128 | 192.168.95.130 | 192.168.95.128 is at 00:0c:29:48:5d:fa |

逐包拆解:
No.1(ARP 请求):
- 以太网头:目的 MAC = ff:ff:ff:ff:ff:ff(广播),源 MAC = 00:0c:29:48:5d:fa(Host A),类型 = 0x0806(ARP)
- ARP 内容:发送方 IP = .128,发送方 MAC = 48:5d:fa;目标 IP = .130,目标 MAC = 00:00:00:00:00:00(还不知道)
- 操作码 = 1(Request)
- 大白话:Host A 在楼道喊:"工号 130 的同事,我是 128,我的 MAC 是 48:5d:fa,你的 MAC 是多少?所有人都听着!"


No.2(ARP 应答):
- 以太网头:目的 MAC = 00:0c:29:48:5d:fa(单播回给 Host A),源 MAC = 00:50:56:37:cb:08(Host B),类型 = 0x0806
- ARP 内容:发送方 IP = .130,发送方 MAC = 37:cb:08;目标 IP = .128,目标 MAC = 48:5d:fa
- 操作码 = 2(Reply)
- 大白话:Host B 举手:"我是 130,我的 MAC 是 37:cb:08,只有 128 你听好了!"


No.3~4(ICMP):
- ARP 表建好了,MAC 地址已知,直接封装以太网帧发 ICMP即ping报文(这就是第 01 篇拆的那个 98 字节包的来源)。

No.5~6(反向 ARP):
- Ping 通后,Host B 也顺便查了 Host A 的 MAC(如果之前没缓存的话),完成双向映射。
- 即这2个反向ARP报文:

- 具体报文内容如下:


5. 验证 ARP 缓存

Flags Mask 列的 C 表示 Complete(已解析完成,缓存有效)。
四、ARP 缓存的生命周期
初学者最容易困惑的问题:"为什么我第二次 ping 就不发 ARP 了?"
因为 ARP 缓存有"保质期":
|--------------------|---------------|--------------------|
| 状态 | 含义 | 持续时间 |
| REACHABLE | 刚解析完,确定可达 | 约 30~60 秒 |
| STALE | 过期了,不确定对方还在不在 | 之后每次发包前会发单播 ARP 刷新 |
| DELAY / PROBE | 正在重新探测 | 几秒内 |
| FAILED | 探测失败,从表里删除 | --- |
用命令查看详细状态:
bash
ip neigh show# 输出类似:# 192.168.95.130 dev ens33 lladdr 00:50:56:37:cb:08 REACHABLE
这就是为什么你上次抓包"先 ICMP 后 ARP"------那不是广播解析,是缓存变成 STALE 后的单播刷新。
五、ARP 故障排查速查
1. 常见问题一:ping 不通,Wireshark 里只有 ARP 请求,没有应答
可能原因:
- 目标机器没开机 / 网卡没 up
- 两台虚拟机不在同一个 VMnet(网段不同)
- 防火墙拦截(少见,但 Ubuntu 默认不拦 ARP)
排查命令:
bash
确认 IP 在同一网段
ip addr show ens33
确认接口是 UP
ip link show ens33
手动发 ARP 请求测试
arping -I ens33 192.168.95.130
看有没有应答
arp -n
2. 常见问题二:ARP 表里有条目,但还是 ping 不通
可能原因:
- MAC 地址缓存了旧的(比如虚拟机克隆后 MAC 变了)
- IP 冲突(两台机器配了同一个 IP)
- 虚拟机配置不对
排查命令:
bash
删除错误条目sudo ip neigh del 192.168.95.130 dev ens33
重新 ping 触发解析
ping -c 1 192.168.95.130
查看是否有 IP 冲突(看同一个 IP 对应多个 MAC)
arp -n# 如果看到同一个 IP 对应两个不同 MAC → IP 冲突了
ifconfig显示NO-CARRIER,ping对端ping不通

可以改虚拟机配置,选择仅主机模式,重启虚拟机:

3. 常见问题三:ARP 表满了
排查命令:
bash
查看 ARP 表条目数
arp -n | wc -l
查看系统 ARP 表大小限制cat /proc/sys/net/ipv4/neigh/default/gc_thresh3
手动清空全部sudo ip neigh flush all
4. 排障速查表
|--------------|----------------|-------------------------------------|
| 现象 | 先看什么 | 命令 |
| ping 不通 | ARP 表有没有条目 | arp -n |
| 只有 ARP 请求没应答 | 对方是否在线、同网段 | ip addr show + ping 对方 |
| ARP 表有但通信失败 | MAC 是否过期/错误 | ip neigh show + sudo ip neigh flush |
| 网络慢、丢包 | 是否有 IP 冲突 | arping -I ens33 <IP> 看几个 MAC 回 |
| 怀疑 ARP 欺骗 | 同一 IP 对应多个 MAC | arp -n 反复观察 |
六、ARP 和后续协议的关系
|---------------------|-----------------------------------------------------------------------------|
| 协议 | 和 ARP 的关系 |
| IP | IP 包要发出去之前,必须先通过 ARP 拿到下一跳的 MAC |
| **ICMP (Ping)** | Ping 之前先 ARP(你第 01 篇的抓包就是证据) |
| TCP/UDP | 第一次发包前也要先 ARP |
| 路由转发 | 路由器收到包后,查路由表决定从哪个口出,再 ARP 查下一跳 MAC |
| Gratuitous ARP | 免费 ARP------自己主动广播"我的 IP 是 X,MAC 是 Y",用来检测 IP 冲突 / 通告 MAC 变了(后面讲 VRRP 时会用到) |
| 代理 ARP | 路由器替别人回答 ARP(老技术,了解即可) |
| IPv6 ND | IPv6 不用 ARP,用邻居发现协议(NDP),本质干一样的事(下一篇会提) |
依赖关系总结:
纯文本
应用层 (HTTP/DNS/...)
↓
传输层 (TCP/UDP)
↓
网络层 (IP)
↓
链路层 (Ethernet II)
↑ 发包前先查
ARP(翻译官:IP → MAC)
**ARP 不是"装在 IP 里面"的,它是和 IP 平级的------都直接装在以太网帧里。** 看 EtherType:0x0800 = IP,0x0806 = ARP,各走各的。
七、总结
今天你亲手做了这些事:
|---------------------------------|--------------------------------|
| 你做了什么 | 学到了什么 |
| ip neigh flush 清空 ARP 缓存 | ARP 表是"记忆",清掉才能看到完整解析过程 |
| ping -c 1 触发通信 | 第一次通信必定先 ARP,后 ICMP |
| Wireshark 抓到 ARP 广播和单播应答 | 请求是广播(ff:ff:ff:ff:ff:ff),应答是单播 |
| 点开 ARP 包看 Opcode=1/2 | 请求是"喊话",应答是"私聊回信" |
| arp -n 查看缓存 | MAC 地址被记住了,下次直接复用 |
| ip neigh show 看 REACHABLE/STALE | 缓存有生命周期,过期会刷新 |
| arping 手动探测 | 排障利器,不依赖 IP 层 |
记住一句话:ARP 是 IP 到 MAC 的"翻译官"------以太网只认 MAC,不认 IP,ARP 负责把 IP 翻译成 MAC。请求广播喊一嗓子,应答单播回一句,翻译完记小本本,下次直接用。
下一篇预告
第 03 篇:VLAN(802.1Q)------ 一台交换机怎么"隔出多个房间"
ARP 解决了"同网段找 MAC"的问题,但如果局域网里机器越来越多,广播风暴、安全隔离、部门之间互串......怎么办?现实中不可能所有设备都挤在同一个广播域里。VLAN 就是给以太网帧"贴标签",把一台物理交换机逻辑上切成多个独立的虚拟局域网。下篇讲 VLAN 标签怎么插进 Ethernet II 帧、VMware 里怎么模拟多 VLAN 环境、以及 trunk/access 端口的区别。
附录:本文命令速查
bash
查看 ARP 表
arp -n
ip neigh show
清空 ARP 缓存sudo ip neigh flush dev ens33sudo ip neigh flush all
手动 ARP 请求(探测)
arping -I ens33 192.168.95.130
查看 ARP 缓存详细状态
ip neigh show
