彻底弄懂 TCP/IP 协议簇 —— 链路层

链路层简介

数据链路层(也简称链路层)处于 TCP/IP 网络体系的第二层,它是物理层与网络层的桥梁。当电信号(也就是 bit 流)在传输介质(如光纤、双绞线等)传输时,不可避免会因为受到外界干扰(称之为噪声)而产生误差,而处于物理层之上的链路层通过采用差错检测与纠错、流量控制等手段,向网络层提供可靠的数据传输服务。

该层是对物理层传输原始比特流的功能的加强,将物理层提供的可能出错的物理连接改造成为逻辑上无差错的数据链路。

以太网

本文主要论述以太网,即Ethernet II,并不对其它局域网标准深入研究。

以太网是一套标准,最初的以太网称为“10 Mb/s以太网”,它的速率是 10 Mb/s,使用的物流地址是 48bit,也就是 6 byte。最后它被 IEEE 轻微修改为 802.3 标准。 需要注意的是,我们现在常用的 Ethernet II 标注和 802.3 标准的帧格式是有一点点区别的,这个会在接下来帧格式详细描述。

CSMA/CD

以太网采用 CSMA/CD的分布式算法来协调一个局域网内的哪些主机可访问共享的传输介质(如网线)。

什么是 CSMA/CD 呢?它的意思是带冲突检测的载波侦听多路访问(Carrier Sense Multiple Access with Collision Detection),下图给出了简洁并准确的解释。 总线型网CSMA/CD络拓扑

上图截取自B站视频,该 BV 通俗易懂解释的了 CSMA/CD,是一个难得的好视频。另外也推荐该老师的网络微课堂系列视频

那为什么要采用 CSMA/CD 呢?

首先我们回顾一下网络拓扑的发展轨迹,在最初网络采用的是总线型拓扑,多个主机共享一个网络总线,当网络中的一个主机要发送数据时,它需要知道共享的网络总线是否处于空闲,否则它往一个非空闲的总线发送数据时就会产生碰撞冲突。

这种总线型网络的结构如下图所示: 总线型网络拓扑

从上图我们可以看到,总线型网络中的有多个主机同时接入到总线上,且任一主机在发送数据时会独占总线,为了解决可能出现的冲突问题,就引出了 CSMA,也就是“载波侦听多路访问”部分。你可以把它想象这样:

“有一条只能容纳一个人通过的小巷子,巷子里的住户想要通过这条巷子时,需要知道是否有人正在这个巷子里行走,若巷子有人则其他住户不能出门,否则就会出现两个人碰头的情况;若没有人,则住户可以出门。”

上面的例子中,小巷子两边的住户就是“多点接入”,或称“多路访问”;住户想要出门时,要先检测巷子内是否有人,这就是“载波侦听”。虽然这个策略能在一定程度上解决碰撞的发生,但无法彻底解决碰撞问题,例如:当两个或多个住户同时检测到巷子是畅通的,就会同时出门,此时碰撞依然会发生,一个住户无法约束其他住户的行为,也就是说它没有冲突检测和发生冲突后的阻止功能。

可以对上面的策略改进,规定住户在出行过程中依然继续监测着巷子,当发生碰撞后,碰撞的双方则掉头回家告诉家里其他人不用出门了,即冲突检测和阻止,这就是 CSMA/CD 策略。下图展示 CSMA/CD 策略的大致流程。 csmacd流程图

这里还有一个细节点,主机在检测总线是否空闲是需要一个间隙的,即主机在检测到总线在一个时间片内没有信号,才认为总线是真正的空闲,这个时间片为 96bit 时间,即 96 个电信号脉冲在介质上传输所消耗的时间。

争用期

上面我们已经大致了解的 CSMA/CD 的原理,结合总线的工作特点:“总线上的主机发送数据,则总线就被独占”。那么主机需要发送的数据至少要灌满总线的一个来回,这样才能进行冲突检测,否则当一个主机发送的数据很少时,在碰撞信号回来时数据都已经发送完了,也就不会对已发送的帧做碰撞检测。这里就引出了“争用期”的概念,我们把传输灌满总线来回所需数据的耗时称为争用期,记作 2τ(注意这是一个来回的时间),τ 表示总线端到端的单程传播时延。

以太网规定争用期为 51.2 us,它的计算方式大致如下:

最初的总线型以太网的最大长度限制为 2500m,中间包括 4 个中继器,也就是 5 根 500m 的铜缆连接起来的。电子在铜缆中的速度为 0.77c,从而得出电子跑一个来回的耗时为:

τ = (2500 * 2)/0.77c = 5000m / (2.31*10^8m/s) * 1000000 ≈ 21.6 us
能传输的 bit = 21.6 us * 10Mbit/s ≈ 216 bit

当然这是最理想的情况,设计者还要考虑到中继的转发延时以及其他安全因素,最终把争用期定义为:512 bit 采用 10Mbit/s 时的传输耗时,即:

争用期 = 512/(10 * 1000 * 1000) * 1000000= 51.2 us

那为什么争用期是 2τ,为什么不是 1τ 或者 3τ?先看下图,它展示了一个碰撞的发生。 争用期

从上图我们可知,当主机 A 在 t = 0 发送数据后,经过 2τ - δ 就能检测到碰撞信号,如果 δ 无限趋近于 0(δ -> 0),也就是主机 A 发出的第一个 bit 即将到达主机 D 时,主机 D 也开始发送数据,那么主机 A 则需要经过无限接近于 2τ 才能收到碰撞信号。这也是为什么争用期时 2τ 的原因。

以太网帧格式

以太网帧格式比较简单,头部由源目 MAC 地址、长度/类型(Ethernet II是类型,802.3是长度)组成,尾部是一个 4 字节的 CRC(冗余校验码),格式如下图: 以太网格式

图片截取自维基百科

以太网帧(一般指 Ethernet II)的大小范围为:[64, 1518] 字节,一般我们只需要关注2层以太网帧,不过你会发现上图在以太网帧下层还会在以太网帧前后附加一些 bit 数据,这些数据是用来让接收方的数据链路层从物理层交互的 bit 流中提取出一个个完整的帧。实际上,物理层上报的数据并不是一个帧紧接着一个帧的,帧与帧之间会有一些特殊的 bit 串分隔开来,头部有 7 字节前导码,用来使接收方时间同步,紧接着 1 字节的帧界定符,它标识着一个帧的开始,另外在帧的尾部带有帧间距 bit 串。下图描述了帧在链路层的传输形式。 以太网帧封装

图片截取自网络

思考一个问题,假如用户数据内包含了一个帧界定符,那接收方能正确提取出以太网帧吗?答案是不能,所以发送方的链路层会在发送帧之前对其负载数据做检查,并把与帧定界符相同的数据转义,接收方收到后提取流程大致如下:

| 数据2 | flag2 | 数据1-2 | dummy_flag | 转义字符 | 数据1-1 | flag1 |

当接收方读取到 flag1 时,它知道一个帧开始了,当读取到一个转义字符,它就知道接下来的一个字符虽然与界定符一样,但是它是数据的一部分,剔除转义字符后继续读取,最终得到的完整帧为:数据1-1 + dummy_flag + 数据 1-2

MTU

MTU(Maximum transmission unit)一般指最大传输单元,即以太网帧能够携带的最大数据,或称有效载荷,它的大小一般为 1500 字节。因为有了链路层的 MTU 限制,因此网络层传递过来的数据若超过了 MTU,就会被分片,使得每一片都小于等于 MTU,这也是为什么 IP 分片产生的原因。

主要特别注意的是,MTU 是针对与出接口,即发送的数据需要与出接口的 MTU 进行比较。

路径MTU

网络中两个主机进行通信,它们之间可能存在多个路径段,比如中间经过了多个路由器,这些中间的链路都有自己的 MTU,我们把整个链路中最小的 MTU 称之为路径MTU。此外,路径 MTU 是可能会变化了,因为通信的链路会发生变化,例如路径上的某个路由器坏了,导致路径路由重构。

当一个数据包经过路径上的某个节点时,可能会被再次分片,因为节点的 MTU 可能比发送主机的 MTU 还要小。一个数据包可以被路径上的多个路由器多次分片。 路径 MTU

上图描述了一个包在路径上的路由器多次分片的情景。

若希望在整个链路上都不想发生分片,则需要在发送数据时保证数据大小小于等于路径 MTU。另外,路径 MTU 在不同方向上也是不一样的,即发送方向上有一个路径 MTU,同样在接受方向也存在一个路径 MTU,它们的大小可能是不一样的。

参考

  1. Etherenet Frame