学完本篇,你会真正理解“一个网络包是如何被封装、转发、路由和分片”的全过程。


#️⃣ 1. 什么是 MAC 地址?它在哪里?长什么样?

✔ MAC 地址是什么?

MAC 地址(Media Access Control Address) 是网卡的物理地址,由厂商烧录在网卡芯片上,48bit。

格式示例:

00:1A:2B:3C:4D:5E
AA-BB-CC-DD-EE-FF

✔ 它在哪里?

你的电脑可以查看:

macOS / Linux:

ifconfig

Windows:

ipconfig /all

网卡芯片上会写一个“物理地址”,那就是 MAC。


✔ 为什么局域网靠 MAC 通信?

局域网在 链路层(L2) 通信,而链路层的身份标识就是 MAC。

只要在同一个局域网(同一个交换机下),通信一定靠 MAC。

链路层就是:

“我只管找到下一跳是谁(MAC),至于他家住哪(IP),我不关心。”


✔ 为什么交换机要学习 MAC?(最关键)

交换机内部有个 MAC 表(Forwarding Table):

MAC 地址      →   来自哪个端口

ASCII 图:

┌─────────────────────────┐
│     交换机 MAC 表        │
├─────────────────────────┤
│ AA:AA:AA:AA:AA:AA → 端口1 │
│ BB:BB:BB:BB:BB:BB → 端口3 │
│ CC:CC:CC:CC:CC:CC → 端口4 │
└─────────────────────────┘

工作过程:

当交换机收到一帧:

src MAC = AA:AA...
dst MAC = CC:CC...

交换机会:

  1. 学习 src MAC → 记住它在哪个端口

  2. 在 MAC 表里找 dst MAC

    • 找到 → 单播转发
    • 找不到 → 广播(发给所有端口)

程序员类比:

MAC 表 = HashMap
map.put(srcMac, port)
map.get(dstMac)

交换机工作就像一个高性能 MAC → 端口号的缓存系统。


#️⃣ 2. 什么是 IP 地址?为什么要有 IP + MAC 两种?

MAC 只能在局域网使用,但互联网这么大,你的电脑不可能记住全球所有 MAC。

于是出现了:IP 地址(Internet Protocol Address)

IP 是全球通用的“逻辑地址”。

✔ 两者关系

  • MAC = 门牌号(物理位置)
  • IP = 家庭住址(逻辑地址)

你住在 304 室(MAC),
但快递寄到 你家的地址(IP)


✔ 为什么要有 ARP?

ARP(Address Resolution Protocol)专门用来:

已知 IP → 查 MAC

流程:

  1. 电脑知道目标 IP

  2. 发 ARP 请求广播:

    谁是 192.168.1.88?请告诉我你的 MAC!
  3. 对方回应:

    我是 192.168.1.88,我的 MAC 是 CC:CC...
  4. 然后再发真实数据包(目标 MAC 正确了)

ARP 就像在一个宿舍楼问:“住 302 的是谁?”


#️⃣ 3. 什么是端口?为什么 TCP、UDP 有端口?

✔ “IP + 端口” 才能定位一个进程

IP 只能定位“设备”,无法定位具体的“应用程序”。

于是有端口(Port):

  • HTTP:80
  • HTTPS:443
  • MySQL:3306
  • Redis:6379

端口范围:

0~65535 (因为端口字段是 16 bit)

✔ Java 程序的端口是怎么来的?

当你写:

ServerSocket server = new ServerSocket(8080);

操作系统会:

  1. 给该进程绑定端口 8080
  2. 在内核的监听表中记录该端口
  3. 当有数据到达 8080 时,转给对应 Java 进程

如果另一个程序也想绑定 8080?

→ 报错:Address already in use(端口冲突)


#️⃣ 4. 网络报文结构(从外到内一层层拆解)

一个网络请求发送时,实际上经过多层“套娃式封装”:

┌─────────────────────────────┐
│         以太网帧 (Layer2)     │   ← 交换机只看这个头
├─────────────────────────────┤
│         IP 包 (Layer3)        │   ← 路由器只看这个头
├─────────────────────────────┤
│         TCP 段 (Layer4)        │   ← 防火墙、负载均衡会看
├─────────────────────────────┤
│         HTTP 数据 (Layer7)     │
└─────────────────────────────┘

✔ 以太网帧结构(交换机只看这个)

┌─────────┬─────────┬─────────────┬────────┐
│ dst MAC │ src MAC │ Type(IP=0x0800) │ 数据   │
└─────────┴─────────┴─────────────┴────────┘

交换机 不看 IP!


✔ IP 包结构(路由器只看这个)

┌────┬────┬────┬──────────┬──────────┐
│TTL │ 协议│ src IP │ dst IP │ 其余字段... │
└────┴────┴────┴──────────┴──────────┘

路由器不会看 MAC,直接看 IP 头


✔ TCP 段结构

┌──────────┬──────────┬────────┐
│ src port │ dst port │ Seq/ACK │
└──────────┴──────────┴────────┘

这是防火墙、负载均衡常用的层。


#️⃣ 5. TTL、MTU、分片(ping 报错的根本原因)

✔ TTL(存活时间)

每经过一个路由器,TTL 减 1。

如果 TTL = 0:

Time Exceeded

也就是 ping 时看到的:

TTL expired in transit

避免网络环路导致数据包永远转来转去。


✔ MTU(最大传输单元)

以太网默认:

MTU = 1500 字节

如果 IP 包太大,路由器会 分片(Fragmentation)

示意图:

[大包] → 分成 → [片1][片2][片3]

如果某个路由器不允许分片,ICMP 会返回:

Fragmentation needed but DF set

#️⃣ 6. 用一张总图总结整个报文封装过程

┌───────────────────────────────────────────────┐
│        应用层:HTTP 数据                       │
├───────────────────────────────────────────────┤
│        传输层:TCP 段(端口)                   │
├───────────────────────────────────────────────┤
│        网络层:IP 包(IP 地址)                │
├───────────────────────────────────────────────┤
│        链路层:以太网帧(MAC 地址)            │
└───────────────────────────────────────────────┘

交换机 → 看 MAC
路由器 → 看 IP
防火墙 → 看 五元组(IP + 端口 + 协议)
负载均衡 → 可以看到 URL / Cookie / Header(L7)

至此,你已经能读懂任何网络报文的结构。