Skip to content

LV050-一次ping的完整旅程 ​

一、 为什么要按时间顺序串一遍 ​

前面几篇是分段讲的:分层(LV001)、封装与帧(LV005)、地址与掩码(LV010)、网关与跨网段(LV015)、设备与转发(LV020)、ARP(LV030)、传输层(LV035)、DHCP(LV040)、调试工具(LV045)。

但真实的通信是一次把好几层都用上,只学分段容易出现"每篇都懂、合起来说不清"的情况。

这一篇按时间顺序把一次 ping 的报文走一遍。设定很具体:

角色地址配置
板子192.168.16.30/24静态,网关 192.168.16.1
PC192.168.16.100/24手工填,同网段
连接方式网线直连(或经同一台交换机)—
一次 ping 在不同接法下的报文走向

二、 场景一:直连同网段的完整流水账 ​

1. 逐步流水账 ​

在 PC 上敲下 ping 192.168.16.30,接下来发生的事按顺序是:

#谁做做什么依据什么判断对应代码/文件
1PC判断目的 IP 与自己是否同网段192.168.16.30 & 255.255.255.0 == 本机网络地址 → 同网段,不走网关—
2PC查 ARP 缓存里有没有 192.168.16.30 的 MAC没有 → 发起 ARP—
3PC广播 ARP 请求:"谁是 192.168.16.30"目的 MAC = FF:FF:FF:FF:FF:FF—
4板子 DM9000收到帧,触发中断(PG6 下降沿)网卡按目的 MAC 过滤后收下dm9000.c
5板子主循环取包 → 送进协议栈每 1 ms 由 lwip_comm_poll() 调用ethernetif.c、lwip_comm.c
6板子 lwIP看以太网帧类型 0x0806 → 交给 ARP类型字段分流ethernet.c、etharp.c
7板子 lwIP记录 PC 的映射,单播回 ARP 应答请求里带了 PC 的 MAC,不必广播etharp.c
8PC收到应答,写入 ARP 缓存之后一段时间不用再问—
9PC构造 ICMP Echo 请求 → 加 IP 头 → 加以太网头(目的 MAC = 板子)目的 IP = 192.168.16.30、协议号 1—
10板子收到帧,类型 0x0800 → 交给 IP—ip4.c
11板子IP 头目的地址是自己 → 协议号 1 → 交给 ICMP—icmp.c
12板子生成 Echo 应答,交换源/目的地址回发—icmp.c
13PC收到应答,ping 打印一行 时间=... TTL=...——

2. 整个过程里最关键的两步 ​

(1)第 1 步决定了"要不要找网关"——同网段就不找。这也是为什么直连实验里网关填错也不影响。

(2)第 7 步的单播决定了后续通信的量级——ARP 只广播一次,之后全靠缓存。如果没有缓存,每个 ICMP 包都会带来一次广播风暴。

3. 第一包为什么慢 ​

再补一个观察:ping 的第一包通常比后续几包慢(经常是几毫秒 vs 零点几毫秒),因为第一包里含了 ARP 的一问一答。

这个现象可以直接反过来用作排错依据:如果连第一包都不通,问题多半在 ARP 或更下面,而不是 IP 以上。

三、 场景二:中间多了一台交换机 ​

1. 流水账一行都不用改 ​

把网线从"直连"改成"各自接到同一台交换机",上面的流水账一行都不用改:

差异说明
板子的 ARP 请求先进交换机交换机看目的 MAC 是广播 → 向其它口泛洪
交换机学到了 PC 与板子的 MAC后续帧就能精准转发,不再泛洪
板子与 PC 的配置完全不变(仍必须同网段)

2. 新增的失败点 ​

从"能否 ping 通"的角度看,直连与同交换机是等价的。新增的失败点只有交换机本身:

  • 是否通电、指示灯是否正常;
  • 端口是否协商成功(百兆/千兆、双工是否匹配);
  • 有没有把两个口接成环(会引发广播风暴,现象是网络时通时断)。

四、 场景三:跨网段通信 ​

1. 流水账在前两步就分岔 ​

现在把板子放在 A 网段、PC 放在 B 网段(中间是路由器):

角色地址
板子192.168.16.30/24,网关 192.168.16.1
PC192.168.1.100/24,网关 192.168.1.1
路由器接口 A = 192.168.16.1,接口 B = 192.168.1.1

这次的流水账:

#谁做关键动作
1PC判断不同网段 → 交给默认网关,而不是直接 ARP 板子
2PCARP 的是网关的 MAC,不是板子的
3PC以太网帧:目的 MAC = 网关,但 IP 头里目的地址仍是 192.168.16.30
4路由器收到帧 → 查路由表 → 从接口 A 转发出去,并重写链路层帧头(源 MAC 换成自己,TTL 减 1)
5板子收到请求,生成应答;目的 IP 是 192.168.1.100 → 不同网段 → 交给自己的网关
6路由器反向转发回 PC

2. 必须记住的结论 ​

IP 头全程不变,以太网头逐跳重写。

这就是"MAC 只在一条链路内有效"的具体含义。也正因为如此,跨网段通信要求双方都能找到网关:

如果板子没配网关(或配了不存在的),它能收到请求(因为请求是路由器送上门的),却发不出去应答——现象就是"PC 一直超时,但板子日志显示确实收到了包"。这个现象很有辨识度,遇到它直接去查网关,不要怀疑收包路径。

本实验只有直连或同交换机两种接法,所以正确做法就是双方配成同网段,而不是去折腾网关。网关本身的机制见 LV015-网关与跨网段通信。

五、 场景四:从局域网到公网 ​

如果要访问 www.example.com 这种外网地址,还要多两件事:

环节做什么
DNS把域名解析成 IP(否则只能直接敲 IP)
NAT家用路由器把私有地址 192.168.16.30 换成自己的公网地址,并记住"这个连接是谁的",回包再换回来

这也解释了为什么私有地址能重复使用:它只在内网可见,出门就被 NAT 换掉了。

反过来说清本工程的定位:Bootloader 只实现了 IP / ICMP / TCP / UDP / ARP 这一小块,既没有 DHCP 也没有 DNS,也没有公网地址。它的目标始终是"在同一局域网内被 PC 找到并升级",不是上网。

六、 把流水账落回实测输出与排错链 ​

1. 串口实测输出 ​

板子启动后串口会打印(详见 LV020-网络通信实验 第一节):

text
DM9000: ID = 0x90000A46                          ← 网卡认到了,链路层 OK
lwIP: MAC 02-00-00-XX-XX-XX, IP 192.168.16.30    ← 网络层参数就绪
lwIP: RX mode = interrupt (EXTI6 falling edge)   ← 收包路径就绪
lwIP: ready, ping 192.168.16.30 to test          ← 可以开始场景一了

会读这四行,就等于有了四个观测点:任何一行不对,排查范围立刻缩小一个层级。

2. 一张排错决策树 ​

把前面几篇合起来,得到一条从下往上的排查链(顺序不能反):

text
网口灯亮吗? ── 不亮 ──▶ 网线 / 对端 / PHY 上电
  │亮
  ▼
串口有 DM9000: ID = 0x90000A46 吗? ── 没有 ──▶ FSMC 初始化 / 片选 / 总线时序
  │有
  ▼
PC 拿到的是 169.254.x.x 吗? ── 是 ──▶ 地址没配好,手工填同网段 IP
  │不是
  ▼
两边同网段吗?(IP & 掩码 比对) ── 不同 ──▶ 改成同网段
  │同
  ▼
PC 上 arp -a 能看到板子的 IP 吗? ── 看不到 ──▶ ARP 没通:收包模式 / 中断标志 / 交换机
  │看到
  ▼
还是 ping 不通 ──▶ 才轮到查协议栈上层(ICMP、收发缓冲、计数统计)

这条链的价值在于:绝大多数"ping 不通"都发生在最上面三层,而不是 lwIP。

3. 两个与 lwIP 相关的现象 ​

现象原理
第一次 ping 慢、后续快第一包含 ARP 一问一答
ping 通但 TCP 连不上说明 IP / ICMP / ARP 都好,问题在传输层——多半是端口被占或单连接策略(见 网络通信实验 第三节)

七、 小结与参考资料 ​

1. 本篇小结 ​

  • 一次 ping 会把分层、封装、IP 与掩码、设备转发、ARP 全部用上,是检验网络配置最省事的工具。
  • 同网段:不走网关,直接 ARP 目的 IP;跨网段:交给网关,ARP 的是网关。
  • IP 头全程不变,以太网头逐跳重写。
  • 直连与同交换机在"能否 ping 通"上等价,配置要求也相同:双方同网段。
  • 上网还要 DNS 与 NAT;本工程的目标不是上网,而是在局域网内被找到。
  • 排查顺序永远从物理层往上:先灯、再网卡 ID、再地址、再 ARP,最后才是协议栈。

2. 参考资料 ​


本文档由 markdowncli 技能辅助生成