0、前言
本文大多数图片都来自于 B站UP主:湖科大教书匠 的教学视频,对高军老师及其团队制作出这么优质的课程表示感谢。文章增加了部分个人理解,内容并不是对视频的静态化翻译。
1、概述
1.1、数据链路层在计算机网络体系中的位置
1.2、对 MAC 地址的理解
MAC 地址并不是针对主机(或路由器)而言的,而是针对网卡(或路由器的接口)而言的,每一张网卡都有一个MAC地址:
- 一台主机一般有以太网卡(有线网卡,Ethernet)和无线网卡(WLAN,Wireless LAN),在 Windows 系统上可以通过
ipconfig /all
进行查看
- 路由器的每一个接口可以认为是一张网卡(暂时这么认为),下图是通过 Packet Tracer 查看 Router1941 的配置项
1.3、认识网卡(网络适配器)
- 核心芯片:其中有 数据缓冲区,用于缓冲发送或接收到的数据
- PCI 接口:Linux 系统中可以通过
lspci
来查看 PCI 设备,可以认为是ls pci
的组合命令。
曾在个人笔记本上安装 CentOS 7、Kali Linux、Ubuntu等,但无论怎么重装,都出现 WiFi 不可用的问题,也就是无线网卡的问题。在寻找解决方案的过程中,会遇到一些文章中提到lspci | grep net
来查看网卡 - EEPROM:可编程电可擦除只读芯片,存储 MAC 地址
除了物理网卡,还要一些虚拟网卡,例如:
- 在 Linux 系统上使用
ip address
可以查看到有一张名为lo
的网卡,这就是用于本地回环测试1的网卡 - 在使用 VMWare 等虚拟机软件后,可以看到操作系统中会多出一些
VMnet8
、VMnet1
这些用于和虚拟机通信的虚拟网卡
二、数据链路层的机制(理论)
数据链路层要解决的三个问题:
- 封装成帧和透明传输
- 差错检测
- 可靠传输
2.1、封装成帧和透明传输
2.1.1、封装成帧
要考虑的问题是:上层传递过来的数据最终以 bit 流(面向比特的链路) 或 byte 流(面向字节的链路),需要一种机制使得接收方能够区分数据的开始和数据结束。
方式一:插入帧定界符
PPP 协议采用该方案,存在缺陷的原理如下:
- 约定起始符号和终止符号(可以是同一个,记为 FLAG,PPP 协议中该值是 0x7E,二进制形式为 01111110)
- 遇到第一个 FLAG 认为是数据开始,遇到第二个 FLAG 认为是数据结束
方式二:采用帧间间隔
以太网协议采用该方案,原理如下:
- 插入前导码(同步+起始符的功能)
- 传输完一个帧后,等待一个帧间间隔(28us)后再传输下一个帧。
相当于采用 NULL
来作为终止符,即一段时间不传输数据,来接收方来确定帧结束
2.1.2、透明传输(完善的帧定界符方案)
帧定界符方案存在一个问题:如果上层传递过来的数据中存在 FLAG 这个值,那么就会发生误判,如下图所示
透明传输要解决的正是这个问题:让数据荷载中可以包含任意数据。上层不需要关系底层细节,即透明。
相似问题:
- 如何在一个字符串中包含
"
符号?
基于字节的解决方案:使用转义字符(ESC,PPP协议中该值为 0x7D)
综上所述,使用透明传输需要发送方和接收方都对数据进行额外的处理(开销),具体过程如下:
- 发送方发送数据时,扫描帧的数据荷载部分,对其中的
FLAG
、ESC
都进行转义(细节),即在前面插入 1B 的ESC
字符 - 接收方接收数据时,扫描帧的数据荷载部分,当发现
ESC
时,就不对下一个字节的数据进行判断,直接提取即可。当需要判断的时候发现FLAG
,那么说明数据结束。
基于比特的解决方案:改造数据荷载,让数据荷载中不出现 FLAG
(01111110) 这个序列,且接收方能够还原
FLAG
中间出现连续 6 位 1,因此只需要遍历数据荷载中的每一比特,当发现 5 个连续比特位为 1 时,再其后插入 1 位 0,即 5110
。
4110
、3110
、2110
、1110
、0110
这些方案都是可行的,都可以保证数据荷载中不会出现 FLAG 这个序列。之所以选择 5110,是因为它的开销最小,假如采用 0110,那么相当于在原来数据的基础上扩充了一倍的数据长度,那么 1500 B 的数据荷载就需要分成两次进行发送,增加了开销。- PPP 协议中发送除了插入转义字符外,还会将其后的数据(待转义的字节数据,即 FLAG 和 ESC)和
0x20
进行异或。接收方在提取该字符时,会再和0x20
进行异或来还原。这本质上也是保证数据荷载中不会出现 FLAG 字符,和基于比特的解决方案在本质上异曲同工,但个人这里有点疑惑,因为感觉这个步骤是可以没有的,不理解为什么 PPP 协议要这么做?
2.2、差错检测
2.2.1、奇偶校验
奇校验:添加一个比特位,使得数据中比特 1
的总数为奇数
偶校验:添加一个比特位,使得数据中比特 1
的总数为偶数
2.2.2、CRC 循环冗余校验
以太网(Ethernet)、PPP 协议中均采用该方式进行差错检测,且以太网中如果出现帧错误,会直接丢弃帧,而不会重传。
帧错误的情况
- MAC 帧的长度不是 8k bit(其中 k = 1,2,…)。即字节流
- MAC 帧长度不在 [64, 1518] 之间
- FCS 帧检测错误
FCS 的计算过程
-
发送方和接收方约定生成多项式,例如,
G(X) = X^4 + X^2 + X + 1
-
发送方:数据对齐、模二除法(异或)
若生成多项式 是 n 阶多项式,则在待发送数据后面补 n-1 个 0。最后得到的余数即为 FCS(帧检验序列,n-1 位)
-
接收方:模二除法(异或)
接收数据后,用约定的生成多项式进行模二除法,如果最后能够整除,则认为没有出现错误,否则一定出现错误。
2.2.3、海明码(纠错码)
以太网(Ethernet)并没有使用,成本太高,效率低。
原理:TODO
2.3、可靠传输
三、相关协议
3.1、以太网协议(802.3标准)
3.1.1、MAC 帧
帧的数据荷载部分不宜过长或过短,其优缺点分别为:
长的数据载荷,控制字段的占比低,相当于提高了数据的发送效率(正常情况)。但帧比特位的增加也意味着帧发生错误的概率增加了,且出错后的重传开销也增加,需要发送更多的数据。(异常情况)
短的数据荷载,控制字段的占比高,相当于降低了数据的发送效率(正常情况)。但帧比特位的减少也意味着帧发生错误的概率降低了,且出错后的重传开销也降低,只需要发送很少的数据。(异常情况)
此外,帧不能过短似乎还和帧间间隔?载波监听碰撞检测有关,有待进一步补充(TODO)
3.1.2、MAC 地址
MAC 地址是一个 48 bit 的数字,假设自左向右地址依次增大 (注意是假设),如下图所示
其中,bits[0] 表示单播(0)或多播(1)地址,bits[1] 表示全球管理(0)或本地管理(1)。
蛋疼的点:MAC 地址的表示逻辑和 IP 地址的表示逻辑并不统一。 原因在于,MAC 地址在表示的时候,是以字节为单位进行表示的,左边是字节低位,右边是字节高位。因此在表示上,上面的比特数组变成了下面的形式
3.2、PPP 协议
3.3、无线局域网协议(802.11标准)
四、局域网(LAN)的实现
4.1、以太网(Ethernet)
4.2、无线局域网(Wireless LAN)
五、虚拟局域网(VLAN)
六、待解决的问题
- 查看虚拟网卡
VMnet1
,发现其 MAC 地址为 00-50-56-C0-00-01,为什么 bits[1] 是 0 而不是 1 呢? - CRC 检测的数学原理是什么?是100%正确的吗?FCS 错误,一定错误这是容易理解的。但 FCS 检验正确,但实际发生错误,是否存在这种可能性呢?
目的 IP 地址为
127.x.y.z
的都称为回环地址,不仅仅是 127.0.0.1,这只是该 A 类地址中最小的一个。而localhost
常在 host 文件中被解析为 127.0.0.1 而已。 ↩︎