前言
学到网络层和数据链路层时,最容易混在一起的几个问题是:
- 客户端怎么知道下一跳是谁?
- ARP 到底在查什么?
- 源 MAC 是谁决定的?
- 交换机和路由器分别看什么?
- IP 包里的源 IP、目标 IP 会不会变?
- 每一跳到底是不是都重新封装?
这篇文章只讲一件事:
一个 HTTP 请求封装成 IP 包后,是如何被 MAC 帧一跳一跳送到目标服务器的。
动画先看一遍
下面这张动画图展示了完整主线:客户端封装完整协议栈,中间交换机按 MAC 转发,路由器拆帧看 IP,再为下一跳重新封装 MAC 帧。
先记住一句话:
IP 负责最终目标,MAC 负责当前这一跳。
1. 从 HTTP 到 TCP,再到 IP
浏览器发请求时,最开始是应用层数据:
1 | GET /api/user |
传输层会把 HTTP 数据交给 TCP,TCP 加上:
1 | 源端口 |
网络层再把 TCP 段封装成 IP 包,IP 头里有:
1 | 源 IP |
比如:
1 | 源 IP = 192.168.1.10 |
到这里,数据还不能直接发到网线上。IP 包必须继续交给数据链路层,封装成当前链路能发送的帧。
2. 客户端怎么知道下一跳是谁
客户端不是先问路由器“下一跳是谁”。
它会先查自己的本机路由表。
电脑联网时,通常会通过 DHCP 拿到这些配置:
1 | 本机 IP:192.168.1.10 |
操作系统会据此生成路由表,简化后类似:
1 | 目标网段 下一跳 |
如果目标 IP 是:
1 | 192.168.1.20 |
系统发现它在本地网段,就直接发给这台机器。
如果目标 IP 是:
1 | 93.184.216.34 |
系统发现它不在本地网段,于是命中默认路由:
1 | 下一跳 = 192.168.1.1 |
所以:
路由表决定下一跳 IP。
3. ARP 查的是下一跳 MAC
知道下一跳 IP 还不够。
在以太网 / Wi-Fi 这样的二层网络里,真正发送帧时需要目标 MAC。
于是客户端会查 ARP 缓存:
1 | 192.168.1.1 -> AA:BB:CC:DD:EE:FF |
如果缓存里没有,就发 ARP 广播:
1 | 目标 MAC:FF:FF:FF:FF:FF:FF |
同一个广播域里的设备都会收到这个问题,但只有 192.168.1.1 会回复:
1 | 我是 192.168.1.1,我的 MAC 是 AA:BB:CC:DD:EE:FF。 |
客户端拿到结果后写入 ARP 缓存,后续一段时间可以直接使用。
所以:
ARP 不是查最终服务器的 MAC,而是查当前下一跳 IP 对应的 MAC。
只有当目标 IP 本来就在本地网段时,ARP 才会直接查询目标主机的 MAC。
4. 源 MAC 是怎么确定的
源 MAC 来自当前要发出去的网络接口。
你的电脑可能有多个网卡:
1 | Wi-Fi 网卡 |
操作系统先查路由表,决定这个 IP 包从哪个接口出去。
如果走 Wi-Fi:
1 | 源 MAC = Wi-Fi 网卡 MAC |
如果走有线:
1 | 源 MAC = 有线网卡 MAC |
路由器也是一样。路由器有多个接口:
1 | LAN 口 |
路由器决定从哪个出口转发,就用哪个出口接口的 MAC 作为源 MAC。
5. 数据链路帧里装着 IP 包
以太网帧和 IP 包是嵌套关系。
不是“数据链路层同时带源 MAC、目标 MAC、源 IP、目标 IP”。
更准确是:
1 | 以太网帧 { |
比如客户端发给家用路由器时:
1 | 帧头: |
这就是:
1 | 目标 MAC = 当前这一跳 |
6. 交换机做什么
交换机主要工作在数据链路层。
它收到以太网帧后,看帧头里的目标 MAC:
1 | 目标 MAC = 家用路由器 MAC |
然后查自己的 MAC 地址表:
1 | MAC 地址 端口 |
如果知道目标 MAC 在哪个端口,就把整个帧转发到对应端口。
注意:
交换机通常不拆 IP 包,也不理解 HTTP,它只是按 MAC 转发帧。
所以不要说“交换机把 IP 包发给目标 MAC”,更准确是:
交换机把整个数据链路帧转发到目标 MAC 所在端口。
7. 路由器做什么
路由器收到帧后,先看目标 MAC。
如果目标 MAC 是自己的某个接口 MAC,就收下这一帧:
1 | 目标 MAC = 家用路由器 LAN 口 MAC |
然后路由器拆掉数据链路层帧,取出里面的 IP 包。
接着看 IP 包里的目标 IP:
1 | 目标 IP = 93.184.216.34 |
路由器查自己的路由表,决定下一跳和出口接口。
例如:
1 | 目标网段 下一跳 |
查到下一跳后,路由器同样需要知道下一跳 MAC。
如果 ARP 缓存里没有,就在出口所在链路上发 ARP:
1 | 谁是下一跳 IP?告诉我你的 MAC。 |
拿到下一跳 MAC 后,路由器重新封装新的二层帧:
1 | 源 MAC = 路由器出口接口 MAC |
里面仍然装着那个 IP 包。
所以:
路由器重新封装的是二层 MAC 帧,不是每一跳都重新造一个全新的 IP 包。
8. 路由器会不会修改 IP 包
通常情况下,IP 包里的目标 IP 保持不变。
1 | 目标 IP = 93.184.216.34 |
路由器每转发一次,通常会修改:
1 | TTL 减 1 |
如果经过 NAT,还可能修改:
1 | 源 IP |
比如你家里设备访问公网:
1 | 内网源 IP = 192.168.1.10 |
经过家用路由器 NAT 后,出公网时可能变成:
1 | 公网源 IP = 运营商分配的公网 IP |
注意:
跨网段不等于一定 NAT。
跨网段一定需要路由,但 NAT 通常发生在私网访问公网,或者某些网络边界需要地址转换的场景。
9. 是不是所有网络传输都要 MAC
在以太网和 Wi-Fi 里,通常要用 MAC 地址。
但更准确地说:
IP 包必须被某种链路层协议承载,不能直接在物理网络里裸传。
日常局域网里,这个链路层协议通常是:
1 | 以太网帧 / Wi-Fi 帧 |
它们使用 MAC 地址。
但某些点对点链路、隧道或其他链路层技术,不一定使用传统以太网 MAC 转发。
所以可以这样区分:
1 | IP 可以不经过 TCP / UDP,比如 ICMP ping。 |
例如:
1 | HTTP -> TCP -> IP -> 以太网/Wi-Fi |
ICMP 没有 TCP/UDP,但仍然需要链路层承载。
10. 不同网络包分别怎么走
前面一直拿 HTTP 请求举例,但要注意:
不是只有 HTTP 数据才走这套链路,只要数据要发到网络上,就必须被底层协议承载。
区别只在于:它从哪一层开始,经过哪些协议。
DNS 查询
DNS 是应用层协议,用来查询域名对应的 IP。
比如:
1 | example.com 的 A 记录是什么? |
它通常这样封装:
1 | DNS 查询 |
所以:
1 | DNS -> UDP/TCP -> IP -> MAC -> 物理层 |
DNS 查询本身不是 HTTP 请求,它只是为了帮后面的 HTTP 请求找到目标服务器 IP。
TCP 三次握手
TCP 三次握手时,通常还没有 HTTP 请求。
三次握手传的是 TCP 控制报文:
1 | SYN |
每一个握手包也要往下封装:
1 | TCP SYN |
所以:
1 | TCP 握手包 -> IP -> MAC -> 物理层 |
HTTP 请求是在 TCP 连接建立之后才发送的。
HTTPS 请求
如果访问的是 HTTPS,通常会经历:
1 | TCP 三次握手 |
TLS 握手数据本身也要通过 TCP 传输:
1 | TLS 握手数据 |
HTTP 数据在 TLS 加密后,也继续走:
1 | HTTP |
ICMP ping
ping 常用 ICMP。
ICMP 不走 TCP,也不走 UDP,它直接由 IP 承载:
1 | ICMP Echo Request |
所以:
1 | IP 可以不经过 TCP / UDP。 |
但 ICMP 仍然要经过数据链路层和物理层。
ARP 查询
ARP 更特殊。
ARP 的目的就是在局域网里查询:
1 | 这个 IP 对应哪个 MAC? |
它不走 IP,因为它本来就是为 IP 层准备下一跳 MAC 的。
ARP 通常直接封装在二层帧里:
1 | ARP Request |
所以:
1 | ARP -> MAC -> 物理层 |
这也是为什么 ARP 广播只能在同一个广播域里工作,不能跨路由器到远方网络里广播。
小结
把它们放在一起看:
1 | HTTP/1.1 -> TCP -> IP -> MAC -> 物理层 |
这就是为什么不能把网络理解成“只有 HTTP 请求才走完整链路”。
真正的规则是:
每一种网络数据都有自己的起点层,但只要要离开本机,就必须继续交给下面的层来承载。
11. 整个链路总结
把完整过程压缩一下:
1 | 1. HTTP 数据生成 |
最关键的几句话:
1 | 客户端和每个路由器都会查路由表决定下一跳。 |
一句话:
IP 包负责“最终去哪”,MAC 帧负责“这一跳交给谁”;路由器决定下一跳,交换机把帧送到这一跳的目标 MAC。