前面学习了第一层,我们知道了物理层的大致作用,了解了用线缆构建一个网络,并知晓了相关设备。
那么如何从一台设备向另一台设备发消息?
要达到这个目的,光靠第一层的硬件显然是不够的。

OSI第二层的作用

作为大名鼎鼎的“数据链路层”,其作用有:使局域网中机器相互连接,侦测传输错误 。他还有个著名的“跟班”:交换机(也就是常说的Switch)

注意,这里说的是“侦测”,而不是“修正”。

MAC地址——唯一标识

目前网络上的情况稍有复杂:虽然有时我们想和所有机器通信(好比现实世界中对着大家说话),但是大部分时候,我们每次都是与单独的一台机器通信。
那么,“茫茫机海中,我与谁相逢 ?” …
为了定位某台机器,就需要给每台机器一个:“身份证”了。网络的先驱们于是在OSI的第二层创建了一个标识,用于标明每一台机器“是谁”,这个标识被称为 MAC地址

但其实,并不是每一台机器都有一个(独立的)MAC地址作为标识。
大家想啊,既然我们处于OSI第二层,离第一层只有“咫尺之距”,因此MAC地址是和硬件设备有关的 —— 网卡。

网卡上最令我印象深刻的就是连着的RJ45接口(母头)。

可以说,MAC地址其实是网卡的地址,而不是每台机器的地址。因此,MAC地址用于在网络中唯一标识一个网卡,一个电脑会有一个或多个网卡,每个网卡都有自己的MAC地址。

MAC地址的概念

说起来,我们还要找“二进制”好好聊聊!
之前笔者提到过,在信息技术领域,我们用0和1来代表电信号的高电平和低电平,或说两种状态(开/关)。
计算机中的许多元件都可以达到这两种状态,分别用0和1表示,用来计算或存储数据。
例如半导体通电表示1,不通电表示0,CPU等半导体芯片就是这样计算的。这样运算 的有点便是 统一标识、规则简单、节省设备。

MAC地址以十六进制编码
十六进制想必也不用多说,由0-9、A-F共同构成的字码。
而MAC通常表示形式如下: ​​​00:0c:29:10:5a:55​

MAC地址编码
如上表示,MAC地址以6个字节编码(48个二进制位),每两个字节由冒号隔开。
一个字节(Byte)是指明一定量的数据的信息元。例如:一个500GB的硬盘,其实就是500个G的Byte的容量。G是英语giga的意思,表示千兆,即十亿,10的9次方。因此500GB就有大约500000000000个字节。

为什么说“大约”?
精确来看,1GB=1024MB=1024X1024KB=1024X1024X1024B,而硬盘厂商设计时按1GB=1000MB近似计算。

但是现在有个问题,我们如何保证每一块网卡的MAC地址不会和世界上已经存在的网卡地址重复呢?难道不会搞错吗?
一般来说不必考虑此问题。因为一个网卡制造商会购买MAC地址,更确切地说是MAC地址的区块。
MAC地址最前面三个字节是IEEE分配的,后面三个字节由制造商自行分配。这样的话,只要生产商保证自己生产的每块网卡后面使用不同的三个字节,就不会有重复MAC地址了。

特殊的MAC地址

在众多的MAC地址中,有一个地址很特殊——其每一个二进制位都是1: ​​ff:ff:ff:ff:ff:ff​​ 它被称为 广播地址
广播,广而播之。顾名思义,广播地址可以代表任意一个网卡,因此发向广播地址的信息就会发送到所在网络的所有网卡上。

好了,现在我们既已知晓如何用OSI第一层将机器连起来,并用第二层来标识每一台机器(的网卡)。那么是时候定义一个互通所需的语言了。

链路层的语言——以太网协议

它规定了机器之间交换信息的格式。

在网络中,我们通常将通信所用的语言成为“协议”。

在第二层众多的协议中,我们“一眼看中了” Ethernet,即以太网 。 以太网协议并不是第二层中唯一的协议,但却是最常用的。

协议的作用
网络是为了交换信息而生的,网络中传输的都是0/1这样的二进制数据。因此,我们极有可能收到如下信息:
0110101110110101100011001
但是就轮到我们懵逼了。这什么鬼…

协议就是被用来定义用什么样的信息、以什么样的顺序传输。

在传输的信息里,要包含:

  • 发送方地址
  • 接收方地址
  • 信息的实际内容

这样的一个信息单元的总,术语称之为 数据帧)。帧是OSI第二层中传输的数据单元,可以将其看做数据包。

以太网中帧的形式
现在有一个问题:在一个帧中,到底是发送方的MAC地址在前还是接收方的在前?
为了回答这个问题,我们需要换位思考,想象自己就是那台接收信息的机器。

对于机器来说,发送方的 MAC 地址和接收方的 MAC 地址,哪一个更有价值呢?

网络的先驱者们认为接收方的 MAC 地址对一台机器来说更有价值,因为可以立即得知信息是不是发给我们的。如果信息是发给我们的,那么我们阅读信息;如果不是发给我们的,那么大可不必理会。

因此我们在一个帧中,将接收方的 MAC 地址(也叫 MAC 目标地址)放在前,后面跟着发送方的 MAC 地址(也叫 MAC 源地址)。目前我们的以太网帧大致如下:

自学网络协议(三):OSI第二层——机器通信那点事_数据链路层


我们知道,OSI七层模型在发送发发送信息时,需要从上到下依次穿过OSI各层:

自学网络协议(三):OSI第二层——机器通信那点事_数据链路层_02


就是说,在穿越第 2 层前,我们需要穿越第 3 层,这样,第 3 层就可以告诉第 2 层在第 3 层使用的协议是什么了。

这很有用,因为当信息到达接收方的时侯,接收方的机器的第 2 层首先检验 MAC 目标地址,如果和自己的 MAC 地址一样,那么接收方的机器的第 2 层需要将信息发送到第 3 层的对应协议。

在接收方,需要反向穿越 OSI,如下图所示:

自学网络协议(三):OSI第二层——机器通信那点事_MAC地址_03


至此,我们的以太网帧变成了这样:

自学网络协议(三):OSI第二层——机器通信那点事_mac地址_04

还没完!
和一个完整的帧段相比,还缺了:

  • 要发送的信息本身
  • 错误检测

我们应该将这两个信息放在第3层时候用的协议后面。

不少人应该会对“错误检测”感兴趣:CRC

什么是CRC ?
CRC 是循环冗余校验(Cyclic Redundancy Check)的缩写,这名字也比较抽象。

CRC 是一个数学的值,可以作为要发送的数据的一种代表。

简单说来,CRC 对于每条发送的信息都是不一样的。发送方使用某公式计算出被传送数据所含信息的一个 CRC 值,并将此值附在被传送数据后,接收方则对接收到的同一数据进行相同的计算,得到另一个 CRC 值。

如果这两个 CRC 一致,说明发送中没有出错;如果不一致,说明发送中出现了差错,接收方可要求发送方重新发送该数据。
假设机器 A 发送一条信息给机器 B:

  1. 发送前,机器 A 根据发送的信息,来计算 CRC 值(假设值为 X),将这个值放在一帧的结尾处;
  2. 机器 B 接收到 机器 A 发送来的一帧数据后,也计算一个 CRC 值(假设值为 Y);
  3. 机器 B 比较自己计算出来的 CRC 值(Y)和机器 A 发送过来的帧中的 CRC 值(X);

如果 X 和 Y 相等,说明机器 A 发送的帧和机器 B 收到的帧是一样的;
如果 X 和 Y 不相等,说明发送时出了问题,机器 A 发送的帧和机器 B 收到的帧不一样,就成功检测到了错误

现在我们有了完整的元素,那么我们完整的一帧也就可以“画出”:

自学网络协议(三):OSI第二层——机器通信那点事_MAC地址_05

一帧的大小是多少?
在一帧中,有些元素的大小(尺寸)是不变的。这些元素的集合我们称之为帧头。下图中的粗体表示帧头里的数据:

帧头的格式是固定的,因此我们可以定义其大小:

接收方和发送方的 MAC 地址分别占用 6 个字节;
第 3 层的协议用 2 个字节编码;
CRC 用 4 个字节编码。
6 x 2 + 2 + 4 = 18。

因此以太网的帧头一共有 18 个字节。

当然,也有一种分法是将一帧分为帧头、数据部分、帧尾三部分。接收方和发送方的 MAC 地址和第 3 层使用的协议作为帧头,而 CRC 作为帧尾。

当然了,一帧是有最小尺寸和最大尺寸的 —— 以太网帧的最小尺寸是64字节,最大尺寸是1518字节。

小结:在机器 A 和机器 B 之间交换数据的过程如下:

  1. 机器 A 上的一个应用(application,在 OSI 的第 7 层应用层,以后我们会学习应用层)想要发送数据到机器 B 的应用上;
  2. 在 机器 A 这个发送方这端,此数据从上到下穿过 OSI 的各层;
  3. 到底3层了,发送方的第 3 层去告知第 2 层所使用的协议是什么;
  4. 第 2 层用这些信息,包装成一个帧,通过网络传输;
  5. 机器 B 收到了机器 A 发送的这个帧,首先检查帧头部的第一个元素:接收方的 MAC 地址;
  6. 如果等于机器 B 的 MAC 地址,那么机器 B 读取帧中接下来的信息;
  7. 依据帧中的协议部分,接收方(机器 B)的第 2 层就把数据正确地发送给第 3 层;
  8. 数据在接收方就从下到上,直达机器 B 的应用了。