第一次打开Wireshark抓包学习以太网帧格式时,我对着屏幕找了半天,死活找不到书里说的那8字节前导码。当时我以为是自己抓包姿势不对,后来才明白,前导码和帧起始定界符属于物理层同步信息,在进入网卡MAC层之前已经被消费掉了,抓包工具最终呈现给你的内容,是从目的MAC地址开始的。这个小小的误会让我意识到,很多人对以太网帧格式的理解停留在“背下来一张表”,真到了查丢包、调VLAN、验证协议栈、排查CRC错误的时候,才知道每个字段背后都有一段历史包袱和工程权衡。
这篇内容我会从一个完整的以太网帧出发,把每个字段拆开讲清楚,再带你看抓包工具里的实际呈现、几种高频变体帧的区别,最后用几个排障案例说明这些知识怎么用。适合刚入门的数据通信、嵌入式网络开发者,也适合干了几年但一直靠“面向搜索引擎排障”的工程师把底盘知识补一补。以太网帧格式这东西,看着简单,却是整个网络协议栈最不容出错的一层。
1. 一个以太网帧在线缆上的真实形态
1.1 前导码与SFD:被物理层默默消化掉的8字节
书上给的帧格式顶层视图,通常是从前导码开始:7字节的0x55,紧跟着1字节的0xD5,叫SFD(Start Frame Delimiter,帧起始定界符)。这8字节在抓包里永远看不到,但它们确实在线缆上存在。
为什么前导码是0x55?0x55的二进制是10101010,这种0101交替的模式可以让接收端PHY芯片快速恢复时钟、完成比特同步。你可以把它理解成对讲机里的“喂喂喂”,让对方先调到同一个信道节奏上。SFD就不一样了,它的值是0xD5,二进制10101011,最后两个连续1是在告诉MAC层:注意,真正的目的MAC地址要来了,从下一个字节开始就是帧头。
到了100Mbps以上的以太网,物理层编码换成了8B/10B、64B/66B这类带时钟恢复的线路编码,MAC层发出的前导码在物理层已经被转成别的符号序列,接收端PHY会重新生成一个前导码再交给MAC。所以从MAC层视角看,前导码仍然存在;从驱动和抓包工具视角看,这8字节已经被剥离了,根本不进入内存。
1.2 标准以太网II帧布局:一张值得刻进脑子里的表
日常讨论的以太网帧,绝大多数是Ethernet II帧,也叫DIX帧,因为它是DEC、Intel、Xerox三家公司在1980年代联合定义的蓝皮书标准。IEEE 802.3后来也兼容了这种格式,并没有强制所有网络都走带长度字段的802.3帧。
| 字段 | 长度 | 说明 |
|---|---|---|
| 前导码 Preamble | 7字节 | 0x55,物理层时钟同步用 |
| SFD | 1字节 | 0xD5,标记帧头开始 |
| 目的MAC DA | 6字节 | 接收方MAC地址 |
| 源MAC SA | 6字节 | 发送方MAC地址 |
| 类型/长度 Type/Len | 2字节 | 小于等于1500表示长度;大于等于1536表示EtherType |
| 数据 Payload | 46-1500字节 | 上层IP报文等 |
| 帧校验 FCS | 4字节 | CRC32校验,覆盖前面所有字段 |
这14字节的MAC头部,加上最多1500字节数据,再加上4字节FCS,凑出了1518字节这个经典最大值。帧的最小长度是64字节,这个数字背后有物理层逻辑,后面单独讲。
1.3 帧是层与层之间的“最后一层外套”
从应用层往下看,层次大概是这样的:HTTP请求先封装成TCP段,TCP段再放进IP报文,IP报文最后被塞进以太网帧的Data区。每一层都相当于给数据穿一件衣服,以太网帧就是出门前的最后一件外套——它负责把你送到同一局域网里的下一站,或者最近的网关。
交换机和网卡在处理帧时有个重要的分工:交换机只关心外套上的收件人门牌号(目的MAC),不关心里面装的是什么;收到帧后查MAC地址表,决定从哪个端口转发,或者泛洪到所有端口。主机网卡则根据目的MAC判断这帧是否和自己相关,如果是就继续剥掉以太网头,把里面IP报文交给网络层。
所以理解帧格式,本质上就是理解设备在链路层到底在看什么、做什么。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 帧头字段拆解:DA、SA与类型/长度字段的工程细节
2.1 目的MAC(DA)的三种形态:单播、组播、广播
热搜词里有人问“以太网帧中da是啥意思”,先直接回答:DA就是Destination Address,目的MAC地址,6字节48bit,它不是数据(Data),也不是数据库(Database),是接收方地址。
DA字段的第一个字节最低位,专门用来标记地址类型。这个bit在以太网术语里叫I/G位(Individual/Group),0表示单播,1表示组播。如果是FF:FF:FF:FF:FF:FF这种全1地址,就是广播地址。
- 单播帧:目的MAC是某个网卡的真实MAC。交换机会查表转发到对应端口,网卡会和自己MAC比对接收。
- 组播帧:目的MAC第一个字节最低位是1,但其余位不全是1。例如LLDP使用01:80:C2:00:00:0E,IPv6的NDP使用33:33:xx:xx:xx:xx。网卡只有加入了这个组播组才会接收。
- 广播帧:目的MAC全FF,所有处于同一广播域的网卡都必须接收。ARP请求就是最典型的广播帧。
为什么判断标准放在第一个字节的最低位而不是最高位?因为以太网线路上每个字节内部是先传最低位的。把单播/组播标记放在第一个传输的bit上,接收方硬件可以在帧到达的头一瞬间就决定要不要继续处理,省下不少功耗。
抓包时特别容易踩的坑是混杂模式。如果你的Wireshark没开启混杂模式,网卡硬件会直接把那些目的MAC不是自己的帧过滤掉,你根本看不到别的设备之间的通信。有些驱动默认不开启混杂模式,需要你手动勾选。
2.2 源MAC(SA):网卡厂商OUI与本地管理地址
源MAC记录的是发送方网卡地址,通常是一个单播地址。前3字节OUI,全称Organizationally Unique Identifier,由IEEE统一分配给厂商,例如00:1A:2B这种就是某个厂商的OUI;后3字节由厂商自己分配,保证自己生产的网卡不重复。所有厂商的MAC合在一起,理论上全球唯一。
但这里有两个例外。
第一个例外是本地管理地址。MAC地址第一个字节的最低位是单播/组播位,第二个最低位(也就是bit1)是本地管理位,为1时表示这不是厂商出厂烧录的地址,而是管理员或软件临时设置的。虚拟机的虚拟网卡、Windows的随机MAC、路由器接口上手工改的MAC,很多都是本地管理地址。
第二个例外是接口可以改MAC。网络设备上命令行敲几行就能把MAC改掉,这在开局和搬迁场景里非常常见。但要注意,改完之后整个二层网络里学习到的地址表都会刷新,如果改成一个已经被别的设备使用的MAC,就可能造成地址冲突、流量错乱。生产环境里不要随便动这个。
2.3 类型/长度字段:同一个位置,两种协议哲学
这个2字节字段从设计之初就有两套解释。
如果值小于等于0x05DC,也就是十进制的1500,它表示后面数据区的实际字节长度,这是IEEE 802.3原始标准里的用法。如果这个字段大于等于0x0600,也就是十进制的1536,它表示EtherType,用来识别上层协议。数值1501到1535之间的空当是故意留出来的,避免两种解释互相歧义。
EtherType的经典值在抓包里经常见到:
| EtherType | 对应协议 |
|---|---|
| 0x0800 | IPv4 |
| 0x0806 | ARP |
| 0x8100 | 802.1Q VLAN标签 |
| 0x86DD | IPv6 |
| 0x88A8 | QinQ(运营商骨干桥接) |
| 0x88CC | LLDP链路层发现协议 |
| 0x88E5 | MACsec加密帧 |
| 0x88F7 | PTP精确时间协议 |
现代网络里几乎所有帧都是Ethernet II格式,所以这个字段绝大多数时候是EtherType。Wireshark就是通过这个值决定第一层解析器用IPv4还是ARP或其他协议。如果你在代码里手写协议解析,第一步永远是读这个2字节字段,这是整个栈的分岔口。
2.4 字段顺序与字节序:抓包时最容易看花眼的地方
以太网在物理线路上发送字节的顺序是先发DA的第一个字节、再发第二个,以此类推。但在每个字节内部,先发的是最低位,也就是常说的LSB first。这和IP/TCP头里使用的网络字节序(大端序)完全是两个维度:TCP头里的2字节端口号是按大端排列,而以太网MAC字段是按字节序逐字节传输,每个字节内部再按bit翻转发出。
很多人在写驱动或FPGA逻辑时,会在这两个概念上绕晕。举个例子,组播MAC地址01:00:5E:00:00:01,线上最先到达的是0x01这个字节的最低位,也就是bit0=1,正好让接收方能立刻识别出这是一个组播帧。而IP报文头里的源端口0x0050,线上先到达的是0x00这个高字节,然后才是0x50,这就是标准的大端序。
写纯软件解析帧的代码时,反而不用操心这些,直接从缓冲区按偏移量读字节就行,16进制显示出来的字段顺序和线上顺序完全一致。只有在做硬件接收、CRC计算、或者自定义帧生成时,才需要认真对待bit级顺序。
3. 载荷边界、最小帧长和FCS:帧格式里的物理层烙印
3.1 为什么最小帧长必须是64字节
以太网最早是半双工共享介质,所有站点接在同一根同轴电缆上。发送前先听介质是否空闲,发送过程中还要一直监听,如果发现别人也在发,就说明碰撞了,立刻停止并退避重传。
这里有个致命问题:如果A发送的帧太短,A可能已经发完了,而B在链路最远端才刚刚开始发送,A就再也没有机会监听到碰撞信号。它会误以为这帧已经成功送达。所以以太网规定,一个站点发送帧的总时间,必须大于信号从线路一端传到另一端再返回的往返时间,这样发送方才能在发送过程中撞见碰撞。
经典以太网模型是10Mbps速率、最大网络跨度2500米(含4个中继器延迟),最坏情况下往返传播时延约51.2微秒。用10Mbps乘以51.2微秒,得到512比特,也就是64字节。这就是最小帧长64字节的来历。
虽然现代交换网络全网全双工,已经不存在碰撞检测了,但64字节这个边界被完整保留。这意味着任何上层IP包太小的时候,发送方必须填充数据到至少46字节,让整个帧达到64字节。比如一个纯TCP ACK,IP头20字节加TCP头20字节,一共才40字节,不够46字节,于是要补6字节填充。所以你抓包看到的纯ACK帧,长度往往不是54字节,而是60字节,省下的那4字节FCS没有计入pcap记录长度。很多人以为54字节就是一个TCP ACK帧的真实大小,其实那是不带填充的理想简化图,真实线缆上是60字节(不含FCS)。
3.2 1500字节MTU与巨型帧:边界不是随意定的
我们常说的MTU 1500,指的是IP层最大可承载的payload大小,不是以太网帧的总长度。一个标准Ethernet II帧的最大长度是14字节头加1500字节IP报文加4字节FCS,等于1518字节。带VLAN标签则变成1522字节。
为什么载荷上限是1500而不是更大?最早考虑是内存缓冲开销、最大时延、以及误码率。在早期网络设备内存按KB计的年代,1500是一个在吞吐、延迟和实现成本之间的折中。这个数字沿用至今,成了全球网络设备的默认值。
在大流量存储、备份场景里,很多人会开巨型帧(Jumbo Frame),把MTU调到9000。这时一个帧最大可以达到14+9000+4=9018字节,帧数量大幅减少,CPU和交换机处理压力随之降低,吞吐可以提升不少。但巨型帧要求源端、目的端、链路上所有交换机全部支持并放行,只要中间有一台设备MTU没改过来,就可能出现大包不通、小包通的现象。
跨三层网络时更麻烦。如果路径上某些设备的MTU不一致,PMTUD(路径MTU发现)靠ICMP不可达消息来通知源端减小包大小,但防火墙经常把这种ICMP消息拦截掉,结果就是网页打不开、文件传不动,查很久都查不出原因。常用
