数据链路层:网络通信的基石与工程实践

前言
当我们谈论网络通信时,IP协议作为网络层的核心,负责将数据包从源主机路由到目标主机。然而,IP包本身并不能直接在物理网络中传输——它需要一个能够在实际链路上可靠传输的"载体"。这就是数据链路层存在的根本意义。
不理解数据链路层的程序员,就像不懂发动机原理的赛车手,可能在直道上跑得很快,但遇到复杂路况就会束手无策。
数据链路层作为网络协议栈的"地基",直接决定了上层应用的性能和可靠性。无论你是开发微服务架构的后端工程师,还是优化移动应用的前端开发者,理解数据链路层都能让你:
-
精准定位网络性能瓶颈
-
设计更高效的通信协议
-
避免低级但致命的网络配置错误
-
深入理解容器网络和云原生架构
本文将从工程实践的角度,带你深入理解数据链路层的核心机制和实现细节。我们将避开枯燥的理论堆砌,聚焦于实际开发中真正有用的知识和技巧。
网络层与数据链路层
数据链路层用来解决相邻主机直接通信的问题。
我们可以用一个寄快递的比喻来帮助我们理解:
把网络通信想象成寄快递:
-
数据链路层(MAC帧) = 快递货车
-
网络层(IP包) = 快递单
具体过程就是:
你要从北京寄包裹到上海:
- 打包:你把物品放进箱子,写上快递单(IP包)
- 发件人:北京XX小区XX号(源IP)
- 收件人:上海XX路XX号(目标IP)
- 第一段运输:北京本地的快递车(MAC帧1)来取件
- 货车车牌:京A12345(源MAC)
- 目的地:北京转运中心(目标MAC)
- 中转:到了北京转运中心
- 拆开外层包装(去掉MAC帧头)
- 查看快递单(IP包没变)
- 重新包装:装上开往上海的货车(MAC帧2)
- 新车牌:沪B67890(新的MAC地址)
- 最终投递:上海本地快递车(MAC帧3)送货到门
- 收件人看到的是完好的快递单(IP包不变)
IP的流动性 = 快递单在整个过程中保持不变
MAC的支持 = 需要不同的货车在不同路段运输
没有货车(MAC帧),快递单(IP包)根本无法移动!
一句话总结:IP地址告诉你最终去哪,MAC地址告诉你当前这段路怎么走。
在之前的网络层文章,我们很多次都是提及IP地址。我们说IP地址具有流动性,但实际上,IP的流动性不是物理上的流动,而是逻辑上的连续性。这种逻辑连续性正是通过MAC层的"接力传递"来实现的。
认识以太网
以太网帧格式
我们现在,局域网的标准,常见的有以太网,令牌环网,无线Lan,也就是WiFi。WiFi与以太网类似,所以我们这里主要讲解以太网的原理。
“以太网” 不是一种具体的网络, 而是一种技术标准; 既包含了数据链路层的内容, 也包含了一些物理层的内容. 例如: 规定了网络拓扑结构, 访问控制方式, 传输速率等
例如以太网中的网线必须使用双绞线; 传输速率有 10M, 100M, 1000M 等
以太网是当前应用最广泛的局域网技术; 和以太网并列的还有令牌环网, 无线LAN 等
我们先来认识一下以太网的帧格式:

其中,数据部分我们称为这个数据帧的有效载荷,范围是46字节到1500字节。可以看到这里的1500就与我们的IP数据包的分片就对上了。
当然,这个有效载荷的长度要求不能小于46,简单来说,46字节这个下限是为了确保整个以太网帧(从目的MAC地址到帧校验序列)的长度不小于64字节。 而64字节是以太网正常运行所必需的“最小帧长”
为了标识每台主机,我们之前了解了Mac地址的有关概念,知道Mac地址是48位的,也就是6字节大小。而我们的以太帧的前12个字节就分别保存着目的Mac地址与源Mac地址。
而后面的CRC,是一种用于检测数据传输或存储后是否出现错误的技术。你可以把它理解成一个数据的“指纹”或“封印”,就是一个用来校验的手段,我们不考虑这个东西,知道有就行。
那么知道了帧结构,我们就需要来回答那固定的几个问题:如何解包封包?
解包封包
这个问题很好回答,我们的解包封包都是采用的“固定大小”的方法。在解包时,接收方之所以能知道边界,正是因为它对帧的“信封”结构有着固定不变的认知。
- 帧头是固定14字节(6字节目标MAC + 6字节源MAC + 2字节类型/长度)。
- 帧尾(CRC)是固定4字节。
所以非常容易就可以做到解包,解包做到了,封包自然就可以做到。
对于我们的类型这个两字节大小的字段,其实它的含义有两种情况:
- 如果这个2字节字段的 数值 ≤ 1500 (0x05DC),那么它就被解释为 “长度”
- 如果这个2字节字段的 数值 ≥ 1536 (0x0600),那么它就被解释为 “类型”
我们报头是固定大小的,但是我们怎么知道要把自己的有效载荷交给上层的哪一种类型协议(不止有IP协议)呢?
而关于类型的解释我们后面讲ARP的时候还会继续认识,现在我们就只需要知道,帧协议类型字段有三种值,分别对应 IP、ARP、RARP协议类型。他们的十六位进制分别是0800、0806、0835。
认识Mac地址
一、核心定义:设备的“身份证”
MAC地址,也叫物理地址或硬件地址,是网络设备(如网卡、手机、路由器)在出厂时被赋予的一个全球唯一的识别码。
一个最贴切的比喻:
-
IP地址 像你的 家庭住址。它可以改变(比如你搬家了,或者在不同的Wi-Fi下会变)。
-
MAC地址 像你的 身份证号码。它从出生(出厂)就固化在你身上,基本上一生不变。
二、MAC地址长什么样?
它由48位(6个字节)的二进制数组成,但为了方便,我们通常用十六进制表示。
常见格式:
-
XX-XX-XX-XX-XX-XX(Windows系统常用,用-连接) -
XX:XX:XX:XX:XX:XX(Linux/macOS系统常用,用:连接) -
XXXX.XXXX.XXXX(思科设备常用,用.连接)
例如: 00-1A-2B-C3-D4-E5
结构解析:
-
前24位:
00-1A-2B→ 厂商代码。由IEEE统一分配,比如这个段可能属于英特尔公司。 -
后24位:
C3-D4-E5→ 设备序列号。由厂商自己分配,确保它生产的每个设备都不重复。
这就保证了:全世界任何两个网络设备的MAC地址都是不同的。
认识MTU
一、核心定义:网络的数据包“限高”
MTU 指的是一个网络接口一次能够发送的最大数据包的大小。
一个生动的比喻:
把网络想象成一条高速公路,数据包就是上面行驶的卡车。
-
MTU 就是这条路上的 “限高杆”。
-
任何超过这个高度的卡车(数据包)都无法通过,必须被拆分或丢弃。
二、MTU的构成:到底什么算“高度”?
这是一个关键点。MTU的大小并不是指整个以太网帧的长度,而是指帧内部有效载荷 的最大长度。
以一个标准的以太网帧为例:
[帧头 14字节][数据载荷][帧尾FCS 4字节]
-
MTU = 数据载荷 的最大长度。
-
对于最常用的 以太网,这个值是 1500 字节。
所以,一个标准以太网帧的总长度是:
14字节(帧头) + 1500字节(数据/MTU) + 4字节(FCS) = 1518字节
结论:我们常说的“MTU 1500”,指的是IP层及其以上的数据(比如TCP头+你的应用数据)最大不能超过1500字节。
MTU 对 IP 协议的影响
一、最直接的影响:强制分片与重组
这是 MTU 对 IP 协议最经典、最直接的影响。
-
IP 协议的设计初衷:是作为一个“尽力而为”的协议,将数据包从源端送到目的端。它本身不关心底层网络能承载多大的包。
-
MTU 的现实限制:但数据链路层(如以太网)有严格的 MTU 限制。一个接口不能发送长度超过 MTU 的帧。
当两者冲突时:如果一个 IP 数据包的长度超过了路径上某条链路的 MTU,IP 协议就必须启动 “分片” 机制。
分片过程:
-
路由器将过大的 IP 数据包分割成多个片段。
-
每个片段都被封装成一个新的、更小的 IP 数据包。
-
这些新数据包拥有独立的 IP 头(其中包含了分片所需的标识、标志和片偏移字段)。
-
这些片段被独立路由转发。
重组过程:
-
分片只在需要的时候进行(路径中的路由器),而重组只在最终的目的主机上进行。
-
目的主机的 IP 层必须接收所有片段,并根据 IP 头中的信息,将它们重新组装成原始的数据包,才能上交传输层。
影响:
-
效率低下:分片和重组是昂贵的操作,消耗路由器和服务器的 CPU 和内存资源。
-
可靠性降低:如果任何一个片段丢失,整个原始 IP 数据包都将无法重组,导致全部重传(即使其他片段都已收到)。
-
网络拥塞:分片会增加网络中数据包的数量,可能加剧拥塞。
二、对 IP 协议头设计的驱动
为了支持分片与重组机制,IP 协议头中专门设计了三个字段:
-
标识:一个唯一的 ID,同一个原始数据包的所有分片都共享这个 ID,以便接收方知道哪些分片属于一起。
-
标志:其中一位是 “不分片”位。如果此位被设置为 1,路由器遇到超过 MTU 的包时会直接丢弃它,并返回一个 ICMP 错误消息。
-
片偏移:指示当前分片在原始 IP 数据包中的位置,以便接收方能按正确顺序重组。
可以说,MTU 的限制是 IP 协议头中包含这些字段的直接原因。


MTU 对 UDP 协议的影响
UDP 协议本身对 MTU 毫无感知,它简单粗暴地将应用层给它的数据打包成数据报送出去,因此非常容易触发 IP 分片,而分片会显著增加数据报丢失和性能下降的风险。
一旦 UDP 携带的数据超过 1472(1500 - 20(IP 首部) - 8(UDP 首部)), 那么就会在网络层分成多个 IP 数据报.
这多个 IP 数据报有任意一个丢失, 都会引起接收端网络层重组失败. 那么这就意味着, 如果 UDP 数据报在网络层被分片, 整个数据被丢失的概率就大大增加了.
MTU 对于 TCP 协议的影响
MTU 对 TCP 协议的影响与对 UDP 的影响截然不同。TCP 通过一种聪明且自动的机制,成功地 规避和化解 了 MTU 带来的问题,从而实现了高性能和高可靠性。
TCP 的设计者预见到了 IP 分片的危害,因此他们在协议中内置了一个关键机制,确保 TCP 数据包在传输过程中几乎永远不会被分片。
这个机制的核心我们之前提到过,它就是 MSS。
TCP 在建立连接的过程中, 通信双方会进行 MSS 协商:
-
当客户端发起 TCP 连接时,它会在 SYN 包中包含一个 MSS 选项,告知服务器:“我的接收缓冲区能处理的最大数据块是 X 字节(通常基于我本地的 MTU 计算得出)。”
-
服务器在 SYN-ACK 包中也包含自己的 MSS 选项。
-
双方比较这两个值,并选择较小的那个 MSS 作为本次连接的通信标准。
MSS 的协商发生在三次握手的第一次和第二次,即 SYN 和 SYN-ACK 包中
通过这次握手,通信双方都明确知道了对方能接受的最大 TCP 数据段大小。此后,任何一方发送数据时,都会保证其 TCP 数据段不超过协商好的 MSS。
值得注意的是,MSS 的值确实是作为 TCP 首部中的选项 存在的:
-
种类:
kind = 2 -
长度:
length = 4字节(其中1字节是kind,1字节是length,2字节是MSS值本身)。 -
位置: 位于 TCP 三次握手的 SYN 和 SYN-ACK 报文的首部选项中。
MSS 和 MTU 的关系:


认识交换机
局域网通信原理

局域网通信的核心目标是在一个本地网络内(例如连接在同一个交换机或路由器下的所有设备),实现设备之间的直接数据交换。
三大技术基石
1. MAC地址:设备的唯一身份证
- 每个网络设备(网卡)都有一个全球唯一的物理地址,即MAC地址。
- 作用:在局域网内部,最终是通过MAC地址来唯一识别和寻找目标设备的,而不是IP地址。
2. 帧:传输的数据单元
- 在局域网中,数据被封装成“帧”进行传输。
- 每个帧都包含两个最关键的信息:
- 目标MAC地址:数据要发给谁。
- 源MAC地址:数据是谁发的。
第三个自然就是我们需要认识的交换机,但是一开始的局域网是没有交换机的,那么此时他们是怎么工作的呢?
倘若没有交换机的局域网
1、当一个局域网出现两台以上的主机,就难免出现发送数据产生干扰的情况。
所以为了保证避免局域网中的数据碰撞的问题,局域网内要保证每时每刻都只有一台主机在使用局域网的资源。
2、如果仍然发生碰撞了,那么涉及的碰撞主机,会进行短暂的休眠,数据链路层有着重发的机制。
所以局域网就像是一个临界资源,一个时刻只有一台主机使用,互斥就是保护临界资源的策略。
3、我们把这整个局域网,叫做一个碰撞域。
4、那么在一个碰撞域中,主机是越多越好,还是越少越好呢?
当然是越少越好,主机越多,碰撞的概率就会增加,所以我们后面引入了交换机的概念。
5、那么在单台主机发送数据帧的时候,数据帧的长度是越长越好还是越短越好
答案是不长不短最好
- 太短 -> 效率低,负担重
- 太长 -> 延迟高,不公平,重传代价大
标准以太网的1500字节MTU(对应约1460字节的TCP MSS)正是这种权衡下的一个“黄金标准”,它在绝大多数通用网络环境中实现了性能与延迟的最佳平衡。
6、知道了底层原理,那么我想问一下大家,如果我们想hei掉一个局域网,我们该怎么做?
最简单的做法肯定就是发送大量的垃圾数据与别人的信息不断发生碰撞!!!
随着一个局域网,碰撞域中的主机越来越多,我们选择引入交换机来划分碰撞域(就相当于把原本的一个碰撞域分割成更小的几块了)。

以这个图为例,我们引入一个交换机后,交换机通过经过一段时间的学习,会知道 MAC地址与端口的对应关系,从而构建MAC地址表。
于是交换机就把这个碰撞域划分为了两个。macA,macD,macB与交换机的Leftmac地址在一个碰撞域,right mac地址与mac C,macE在一个碰撞域。
简单地说,学习之后,E再次给A发消息,就会发现A在左侧碰撞域,从而对右侧不进行转发,所以碰撞只会在左侧碰撞域发生。
一个交换机内部维护着一张非常重要的表,叫做 MAC 地址表 或 转发表。这张表里记录着多个 MAC 地址与其对应端口的映射关系。
交换机是即插即用的,它不需要配置,自己就能学会。这个过程就是我们之前提到的“学习”。
-
当一台设备(比如电脑A,MAC地址为
AA-AA)第一次连接到交换机的 端口1 并发送数据时,交换机就会查看数据帧中的 源MAC地址。 -
然后它就在自己的MAC地址表中记录一条:
MAC地址 AA-AA 位于 端口1。 -
通过这种方式,交换机很快就能学习到所有活跃设备的位置。
注意
以这个图为例

在我们跨局域网通信的时候,比如我们要从主机B发送信息给主机C,他们是不在一个局域网内的。
我们每到一个局域网的路由器时,都会重新封装以太帧,以便进行下一次的传输,直到它抵达目的局域网内。所以我们的报文传输都是以以太帧的形式在数据链路层上面传递的。
每次到了一个路由器,都会把这个以太帧进行解包,获取IP信息,随后根据目的IP地址,我们重新封装以太帧,进行下一次的跳转。
所以,我们必须得知道,以太帧上面的目的mac地址并不是我们的最后的目的地,他就相当于是快递的中转站。
数据报发送,主要依靠的时IP的路由,但是实际在进行转发的过程中,十分依赖mac地址
这也就是为什么我们说:IP决定宏观战略方向,mac决定具体实施路径。
认识ARP
疑惑:如何抵达目的主机
综上所述,我们其实只知道目的主机的IP地址,但是我们做具体转发,是通过mac地址,也就是说,我们需要某种方法,将一个主机的IP地址转化为这个主机特有的mac地址。只有这样,我们才能进行一个转发的操作。
这就引出了我们ARP的概念。
-
我们通信需要IP地址作为最终目标。
-
但在本地网络传输时,需要MAC地址作为“下一跳”的地址。
-
因此,必然需要一个机制,通过IP地址来查询对应的MAC地址。
-
这个机制就是ARP。
理解:ARP的工作场景
试着想象这么一个场景,你在读高中的时候,校长来到你们班,他要求你们班上学号为10的同学出来一下。
此刻,你是你们的班的班主任,但是一般来说,班主任只知道一个学生的名字,并不知道学生的具体学号,所以你肯定会到班上去询问:谁是学号为10的同学。这个其实就是我们ARP协议的工作原理。
ARP的作用就是把Mac地址与IP地址联系起来。请大家记住这个场景,我们后面还会继续使用这个场景帮助大家来理解ARP。
ARP的帧格式
我们在学习以太帧的时候有过这个图:

我们知道,以太帧有两字节的参数来表示它的具体类型,当它十六位为0800的时候,其实才代表这是一个以太帧啊,就是我们平时传递数据的那种。
那么当它的十六位数字为0806的时候,这个以太帧的类型就是ARP请求/应答。
我们可以这样理解ARP层的位置啊:

MAC与ARP其实同属于数据链路层,但是在数据链路层中,我们还可以给MAC帧补上一个ARP层。他们可以形成一个大层内的上下级小层关系。

ARP帧与MAC帧的区别就是它的有效载荷的长度是固定的28字节,其中包含了硬件类型,协议类型等字段。
硬件类型,我们如果是以太网的一般就填1,表示以太网类型。
协议类型的话,一般就是0800表示是一个IP协议(因为网络层不止有IP协议)。
硬件地址长度一般为6,表示mac地址长度为6字节,协议地址长度为4表示IPv4的长度。
op表示类型,表示这是一个ARP应答还是一个ARP请求。
另外四个大家也不陌生了,就是IP地址与MAC地址。指的注意的是,ARP请求的目的mac地址我们是不知道的,所以一般就填0xFFFFFFF表示目的给广播地址,然后由广播地址进行转发。
ARP的工作过程

让我们结合上图,以一个具体的例子来分解每一步。假设:
-
主机A:IP =
192.168.1.10, MAC =AA:AA:AA:AA:AA:AA -
主机C:IP =
192.168.1.20, MAC =BB:BB:BB:BB:BB:BB -
主机A想与主机C通信,但只知道C的IP地址。
第一阶段:ARP请求(广播)
-
检查本地缓存:
- 主机A首先查询自己的ARP缓存表,看是否有
192.168.1.20对应的MAC地址。 - 如果找到,则直接使用该MAC地址,无需发起ARP请求。
- 如果未找到(如图中所示,例如首次通信),则启动ARP过程。
- 主机A首先查询自己的ARP缓存表,看是否有
-
构建ARP请求包:
- 主机A构造一个ARP请求报文。这个报文包含以下关键信息:
发送方IP:192.168.1.10发送方MAC:AA:AA:AA:AA:AA:AA目标IP:192.168.1.20目标MAC:00:00:00:00:00:00(全0,表示未知)
- 操作码 字段被设置为
1,代表这是一个ARP请求。
- 主机A构造一个ARP请求报文。这个报文包含以下关键信息:
-
封装并广播:
- 将这个ARP请求报文封装到一个以太网帧中。
- 该帧的:
- 目标MAC地址 =
FF:FF:FF:FF:FF:FF(广播地址) - 源MAC地址 =
AA:AA:AA:AA:AA:AA - 类型字段 =
0x0806(标识载荷是ARP报文)
- 目标MAC地址 =
- 主机A将这个广播帧发送到网络上。
-
网络传播与处理:
- 交换机收到广播帧后,会将其洪泛到除接收端口外的所有端口。
- 局域网内的所有设备都会收到这个帧。
- 每台设备都会查看ARP请求包内的
目标IP地址。
第二阶段:ARP应答(单播)
-
识别与响应:
- 主机
192.168.1.30、192.168.1.40等设备发现目标IP与自己的IP不匹配,于是静默丢弃该ARP请求包。 - 主机C 发现
目标IP(192.168.1.20) 与自己的IP地址完全匹配。
- 主机
-
构建ARP应答包:
- 主机C构造一个ARP应答报文。这个报文包含以下关键信息:
发送方IP:192.168.1.20(主机C自己的IP)发送方MAC:BB:BB:BB:BB:BB:BB(主机C自己的MAC)目标IP:192.168.1.10(来自请求包中的发送方IP)目标MAC:AA:AA:AA:AA:AA:AA(来自请求包中的发送方MAC)
- 操作码 字段被设置为
2,代表这是一个ARP应答。
- 主机C构造一个ARP应答报文。这个报文包含以下关键信息:
-
封装并单播回复:
- 将这个ARP应答报文封装到一个以太网帧中。
- 该帧的:
- 目标MAC地址 =
AA:AA:AA:AA:AA:AA(直接发给主机A) - 源MAC地址 =
BB:BB:BB:BB:BB:BB - 类型字段 =
0x0806
- 目标MAC地址 =
- 主机C将这个单播帧直接发送给主机A。
第三阶段:学习与通信
-
接收应答与更新缓存:
- 主机A收到ARP应答后,从包中提取出
发送方IP(192.168.1.20) 和发送方MAC(BB:BB:BB:BB:BB:BB)。 - 它将这个
IP-MAC对应关系存入自己的ARP缓存表中,并设置一个有效期(通常为几分钟到20分钟)。未来再次与主机C通信时,无需再发ARP请求。
- 主机A收到ARP应答后,从包中提取出
-
开始通信:
- 此时,主机A已经获得了主机C的MAC地址。
- 它可以将要发送的应用数据,封装成目标IP为
192.168.1.20、目标MAC为BB:BB:BB:BB:BB:BB的以太网帧,进行单播通信。
我们可以通过我们上面说的那个场景啊,你是班主任,你是路由器,你不知道学号为10的学生具体是谁,所以你会跑到班上问:谁是学号为10的学生啊?这个就是你的ARP请求。(已经被封装成了一个以太帧进行广播了)
这个时候,全班学生都听到了你的询问,注意,每一个学生都代表一台主机,每一个学生的名字,就是这个主机的mac地址。
所以,此刻,所有学生听到了询问,那么不是学号为10的学生,就不会有反应,还是自己干自己的事情。但是当事人,就会站起来说:老师,我是学号为10的学生。这个其实就是目标主机给你的ARP应答。
班主任是认识这个学生的,所以校长也就找到了学号为10的学生。
不知道这个过程大家是否理解了。
ARP请求与应答过程是一个经典的 “广播问,单播答” 模型:
- 请求方:以广播形式提出问题:“谁的IP是X.X.X.X?请告诉你的MAC。”
- 应答方:以单播形式精确回答:“我是X.X.X.X,我的MAC是YY:YY:YY:YY:YY:YY。”
这个过程高效地解决了IP地址到MAC地址的动态映射问题,是局域网内设备能够相互寻址和通信的根本保障。
RARP
这个RARP,其实就是一个ARP的反过程啊,我们的IP转MAC地址,其实是比较麻烦的一个过程,但是RARP,MAC转IP地址,就是比较轻松了。
我们这里不再过多赘述,有需求者可以自行了解或者私信问我。
结语
数据链路层作为网络协议栈的基石,承载着将抽象的网络层数据转化为物理信号的关键使命。通过本文的探讨,我们深入理解了:
从技术层面看,数据链路层通过MAC地址寻址、帧封装、差错校验等机制,为上层提供了可靠的相邻节点通信能力。MTU的限制推动了IP协议的分片设计,也催生了TCP的MSS协商这样的优化策略。
从工程价值看,掌握数据链路层原理让开发者能够:
-
精准诊断网络瓶颈(如MTU不匹配导致的性能问题)
-
设计更高效的分布式系统通信机制
-
深入理解现代云网络、容器网络的底层实现
-
避免因网络配置不当导致的隐性故障
从演进趋势看,虽然以太网和ARP等基础协议历经数十年仍然稳定,但新的技术如RDMA、智能网卡等正在数据链路层引发新的变革。理解这些基础原理,为我们拥抱下一代网络技术奠定了坚实基础。
网络编程的真正功力,往往体现在对这些底层细节的深刻理解上。希望本文能帮助读者建立完整的数据链路层知识体系,在复杂的网络问题面前能够游刃有余,直击要害。
