3. 数据链路层核心:帧结构、MAC地址、以太网协议、CSMA/CD机制

数据链路层,说白了就是让数据能在「同一根网线」上的两台设备之间可靠传输。它把网络层的IP包封装成帧,加上头尾,再通过物理介质发出去。我刚开始调网络驱动时,总觉得这层很简单,不就是加个MAC头吗?直到被一个帧校验错误折腾了整整两天……嗯,从那以后我再也不敢小看它了。

3.1 以太网帧结构——数据链路层的「信封」

以太网帧就像一封信。你要把内容(IP包)装进信封,写上收件人和发件人地址,最后贴上邮票(校验码)。这样接收方才能知道这封信是谁发的、该给谁、有没有在路上被撕坏。

目前最常用的是 Ethernet II(DIX 2.0) 帧格式。IEEE 802.3 也有自己的帧格式,但实际网络中 Ethernet II 占了绝对统治地位。我个人习惯直接叫它「标准以太网帧」。

字段 长度(字节) 说明
前导码(Preamble) 7 同步时钟,101010... 交替比特
帧起始定界符(SFD) 1 10101011,标志帧开始
目的MAC地址 6 接收方网卡地址
源MAC地址 6 发送方网卡地址
类型/长度(EtherType) 2 0x0800=IPv4,0x0806=ARP,0x86DD=IPv6
载荷(Payload) 46~1500 上层数据(IP包),不足46字节需填充
帧校验序列(FCS) 4 CRC32校验,检测传输错误

关键点:前导码和SFD属于物理层封装,真正被网卡接收并交给驱动的是从「目的MAC」到「FCS」的部分。很多初学者抓包时看不到前导码,以为丢了数据——其实不是,是工具帮你过滤掉了。

这里有个容易踩的坑:最小帧长度64字节(从目的MAC到FCS)。为什么是64?因为要配合CSMA/CD的冲突检测机制。如果载荷不足46字节,必须填充到46字节。我曾经在写虚拟网卡驱动时忘了做填充,结果发包总是被对端丢弃,查了半天才发现是帧太短了。

3.2 MAC地址——网卡的「身份证」

MAC地址是数据链路层的寻址标识,48位,通常写成6组十六进制数,比如 00:1A:2B:3C:4D:5E。前24位是OUI(组织唯一标识符),由IEEE分配给厂商;后24位是厂商自己分配的序列号。

你想想看,MAC地址理论上全球唯一,但实际中呢?我见过不少山寨网卡用重复的MAC地址,或者虚拟机自动生成的MAC地址冲突。所以别太迷信「全球唯一」,局域网内唯一才是硬道理。

MAC地址有三种类型:

  • 单播地址:第1字节最低位为0,发给单个设备。比如 00:1A:2B:3C:4D:5E。
  • 多播地址:第1字节最低位为1,发给一组设备。比如 01:00:5E:xx:xx:xx(IPv4多播MAC)。
  • 广播地址:全1,FF:FF:FF:FF:FF:FF,发给局域网内所有设备。

小技巧:抓包时看到目的MAC是广播地址,说明这个帧是「吼」给所有人的。ARP请求就是典型的广播帧——「谁是192.168.1.1?告诉我你的MAC地址!」

3.3 以太网协议——从共享介质到交换网络

早期的以太网是总线型拓扑,所有设备共享一根同轴电缆。谁想发数据,谁就抢线。后来演变成星型拓扑,用集线器(Hub)或交换机(Switch)连接。但不管拓扑怎么变,数据链路层的封装格式基本没变。

以太网协议的核心就是封装-解封装的过程:

  1. 发送方把IP包塞进以太网帧的Payload字段。
  2. 填上源MAC、目的MAC、EtherType。
  3. 计算CRC32,填入FCS。
  4. 通过物理层发出去。
  5. 接收方收到后,先检查FCS。如果校验失败,直接丢弃。
  6. 检查目的MAC是否匹配自己(或广播/多播)。不匹配就丢弃。
  7. 匹配则剥掉帧头帧尾,把Payload交给上层协议(根据EtherType判断)。

这里有个细节:EtherType 字段的值如果小于等于1500,它表示的是「长度」;如果大于等于1536,它表示的是「类型」。这是IEEE 802.3和Ethernet II帧格式的区分方式。实际中你几乎只会看到EtherType,因为802.3格式基本被淘汰了。

3.4 CSMA/CD机制——「先听后说,边说边听」

CSMA/CD(载波监听多路访问/冲突检测)是以太网在半双工模式下的介质访问控制方法。说白了就是:发数据前先听听线上有没有人在发,没人发我就发,发的时候还要继续听,如果听到冲突就停止,等一会儿再重试。

具体流程:

  1. 载波监听:发送前监听信道。如果空闲,等待一个帧间间隔(IFS,96比特时间)后开始发送。
  2. 边发边听:发送过程中持续监听。如果检测到冲突(信号电平异常),立即停止发送。
  3. 冲突强化:发送一个32比特的阻塞信号(Jamming Signal),确保所有站点都检测到冲突。
  4. 随机退避:执行截断二进制指数退避算法,等待一个随机时间后重新尝试。

注意:CSMA/CD只在半双工模式下有效。现在的交换式以太网基本都是全双工,发送和接收使用不同的线对,不存在冲突问题,所以CSMA/CD实际上已经被「禁用」了。但理解它对于掌握以太网的历史和原理仍然非常重要。

退避算法的核心是:第n次重试的等待时间在 [0, 2^n - 1] 个时间片(Slot Time)中随机选择,但n最大到10,重试次数最多16次。超过16次就放弃发送,向上层报告错误。

时间片(Slot Time)是CSMA/CD的关键参数。以太网规定Slot Time为512比特时间(10Mbps下是51.2微秒)。这个值决定了冲突域的最大直径。为什么?因为一个站点发送的帧必须在到达最远站点之前就能被检测到冲突。如果网络太长,信号还没传到远端,发送方就已经发完了,那就检测不到冲突了。

我记得有一次帮客户排查一个老旧的10Mbps以太网网络,总是不定时出现大量丢包。用抓包工具一看,全是冲突计数飙升。最后发现是有人用了一根超过200米的细缆,超出了冲突域限制。换成交换机后问题立刻消失——交换机隔离了冲突域。

3.5 知识体系总览

下面这张图把数据链路层核心知识点串起来了。你可以看到帧结构、MAC地址、以太网协议和CSMA/CD之间的关系。

数据链路层核心知识体系 数据链路层核心知识体系 数据链路层 以太网帧结构 MAC地址 以太网协议 CSMA/CD机制 前导码 MAC头 载荷 FCS 单播 多播 广播 封装 解封装 EtherType CRC校验 载波监听 冲突检测 退避算法 核心关系:帧结构是数据封装格式,MAC地址是寻址标识,以太网协议定义封装/解封装规则, CSMA/CD解决半双工模式下的介质访问冲突问题。全双工交换网络已不再需要CSMA/CD。

3.6 实战中的避坑指南

最后分享几个我在实际项目中踩过的坑,希望能帮你少走弯路:

  • MTU问题:以太网帧最大载荷1500字节,加上IP头和TCP头后,TCP的MSS通常是1460字节。我曾经遇到一个应用层协议没做分片,直接发了1600字节的数据,结果在IP层被分片,导致接收方重组失败。后来在应用层强制限制单次发送不超过1400字节,问题解决。
  • MAC地址表溢出:交换机的MAC地址表有容量限制。有一次在一个大型局域网中,有人用脚本伪造了大量源MAC地址,导致交换机MAC表被填满,开始泛洪所有未知单播帧,网络性能急剧下降。这就是MAC泛洪攻击的原理。
  • CRC校验错误:如果网卡或线缆质量不好,FCS校验失败的概率会很高。抓包时如果看到大量Bad FCS的帧,先检查物理层——换根网线试试,往往立竿见影。

一句话总结:数据链路层是网络通信的「地基」。帧结构决定了数据怎么装,MAC地址决定了数据发给谁,以太网协议定义了封装规则,CSMA/CD解决了共享介质的冲突问题。把这层搞透,上层协议栈的分析才能站得稳。