数据链路层最重要的内容是:
本文主要介绍数据链路层的三个基本问题,包括封装成帧、透明传输和差错检测。
由于是数据链路层的第一篇文章,我们首先来简单学习一些数据链路层的基础的知识,先对数据链路层有一定的了解。
数据链路层属于计算机网络的低层。数据链路层使用的信道主要有以下两种类型:
局域网虽然是个网络,但我们并不把局域网放在网络层中讨论。这是因为在网络层要讨论的问题是多个网络互连的问题,是讨论分组怎样从一个网络,通过路由器,转发到另一个网络。在本章中我们研究的是在同一个局域网中,分组怎样从一台主机传送到另一台主机,但并不经过路由器转发。
从整个互联网来看,局域网仍属于数据链路层的范围。
下面看一下两台主机通过互联网进行通信时数据链路层(简称为链路层)所处的地位。
上图表示用户主机 H 1 H_1 H1通过电话线上网,中间经过三个路由器( R 1 R_1 R1, R 2 R_2 R2和 R 3 R_3 R3)连接到远程主机 H 2 H_2 H2。所经过的网络可以是多种的,如电话网、局域网和广域网。当主机 H 1 H_1 H1向 H 2 H_2 H2发送数据时,从协议的层次上看,数据的流动如上图下方所示。主机 H 1 H_1 H1和 H 2 H_2 H2都有完整的五层协议栈,但路由器在转发分组时使用的协议栈只有下面的三层。数据进入路由器后要先从物理层上到网络层,在转发表中找到下一跳的地址后,再下到物理层转发出去。因此,数据从主机 H 1 H_1 H1传送到主机 H 2 H_2 H2需要在路径中的各节点的协议栈向上和向下流动多次,如图中箭头所示。
然而当我们专门研究数据链路层的问题时,在许多情况下我们可以只关心在协议栈中水平方向的各数据链路层。于是,当主机 H 1 H_1 H1向 H 2 H_2 H2发送数据时,我们可以想象数据就是在数据链路层从左向右沿水平方向传送,通过以下这样的链路:
H 1 H_1 H1的链路层→ R 1 R_1 R1的链路层→ R 2 R_2 R2的链路层→ R 3 R_3 R3的链路层→ H 2 H_2 H2的链路层
上图指出,从数据链路层来看, H 1 H_1 H1到 H 2 H_2 H2的通信可以看成由四段不同的链路层通信组成,即: H 1 → R 1 H_1\rightarrow R_1 H1→R1, R 1 → R 2 R_1\rightarrow R_2 R1→R2, R 2 → R 3 R_2\rightarrow R_3 R2→R3和 R 3 → H 2 R_3\rightarrow H_2 R3→H2。这四段不同的链路层可能采用不同的数据链路层协议。
我们在这里要明确一下,“链路”和“数据链路”并不是一回事。
也有人采用另外的术语。这就是把链路分为物理链路和逻辑链路。
早期的数据通信协议曾叫作通信规程(procedure)。因此在数据链路层,规程和协议是同义语。
帧:点对点信道的数据链路层的协议数据单元。
数据链路层把网络层交下来的数据构成帧发送到链路上,以及把接收到的帧中的数据取出并上交给网络层。在互联网中,网络层协议数据单元就是IP数据报(或简称为数据报、分组或包)。
为了把主要精力放在点对点信道的数据链路层协议上,可以采用如下图(a)所示的三层模型。在这种三层模型中,不管在哪一段链路上的通信(主机和路由器之间或两个路由器之间),我们都看成是节点和节点的通信(如图中的节点A和节点B),而每个节点只有下三层—网络层、数据链路层和物理层。
点对点信道的数据链路层在进行通信时的主要步骤如下:
数据链路层不必考虑物理层如何实现比特传输的细节。我们甚至还可以更简单地设想好像是沿着两个数据链路层之间的水平方向把帧直接发送到对方,如上图(b)所示。
数据链路层协议有许多种,但有三个基本问题则是共同的。这三个基本问题是:封装成帧、透明传输和差错检测。下面分别讨论这三个基本问题。
封装成帧(framing)就是在一段数据的前后分别添加首部和尾部,这样就构成了一个帧。
接收端在收到物理层上交的比特流后,就能根据首部和尾部的标记,从收到的比特流中识别帧的开始和结束。下图表示用帧首部和帧尾部封装成帧的一般概念。
显然,为了提高帧的传输效率,应当使帧的数据部分长度尽可能地大于首部和尾部的长度。但是,每一种链路层协议都规定了所能传送的帧的数据部分长度上限——最大传送单元MTU (Maximum Transfer Unit)。下图给出了帧的首部和尾部的位置,以及帧的数据部分与MTU的关系。
当数据是由可打印的ASCI码组成的文本文件时,帧定界可以使用特殊的帧定界符。我们知道,ASCI码是7位编码,一共可组合成128个不同的ASCII码,其中可打印的有95个,而不可打印的控制字符有33个。下图的例子可说明帧定界的概念。
SOH
(Start Of Header)放在一帧的最前面,表示帧的首部开始。EOT
(End Of Transmission)表示帧的结束。请注意,SOH
和EOT
都是控制字符的名称。它们的十六进制编码分别是01(二进制是00000001)和04(二进制是00000100)。SOH
(或EOT
)并不是S
,O
,H
(或E
,O
,T
)三个字符。
当数据在传输中出现差错时,帧定界符的作用更加明显。假定发送端在尚未发送完一个帧时突然出故障,中断了发送。但随后很快又恢复正常,于是重新从头开始发送刚才未发送完的帧。由于使用了帧定界符,接收端就知道前面收到的数据是个不完整的帧(只有首部开始符SOH
而没有传输结束符EOT
),必须丢弃。而后面收到的数据有明确的帧定界符(SOH
和EOT
),因此这是一个完整的帧,应当收下。
由于帧的开始和结束的标记使用专门指明的控制字符,因此,所传输的数据中的任何8比特的组合一定不允许和用作帧定界的控制字符的比特编码一样,否则就会出现帧定界的错误。
SOH
或EOT
这样的帧定界控制字符。可见不管从键盘上输入什么字符都可以放在这样的帧中传输过去,因此这样的传输就是透明传输。SOH
或EOT
这种控制字符一样(如下图所示),数据链路层就会错误地“找到帧的边界”,把部分帧收下(误认为是个完整的帧),而把剩下的那部分数据丢弃(这部分找不到帧定界控制字符SOH
)。像上图所示的帧的传输显然就不是“透明传输”,因为当遇到数据中碰巧出现字符“EOT
”时就传不过去了。数据中的“EOT
”将被接收端错误地解释为“传输结束”的控制字符,而在其后面的数据因找不到“SOH
”被接收端当作无效帧而丢弃。
但实际上在数据中出现的字符“EOT”并非控制字符而仅仅是二进制数据00000100
。前面提到的“透明”是一个很重要的术语。它表示:某一个实际存在的事物看起来却好像不存在一样(例如,你看不见在你前面有块100%透明的玻璃的存在)。“在数据链路层透明传送数据”表示无论什么样的比特组合的数据,都能够按照原样没有差错地通过这个数据链路层。因此,对所传送的数据来说,这些数据就“看不见”数据链路层有什么妨碍数据传输的东西。或者说,数据链路层对这些数据来说是透明的。
为了解决透明传输问题,就必须设法使数据中可能出现的控制字符“SOH
”和“EOT
"在接收端不被解释为控制字符。具体的方法是:发送端的数据链路层在数据中出现控制字符“SOH
”或“EOT
”的前面插入一个转义字符“ESC
”(其十六进制编码是1B
,二进制是00011011
)。而在接收端的数据链路层在把数据送往网络层之前删除这个插入的转义字符。这种方法称为字节填充(byte stuffing)或字符填充(character stuffing)。
如果转义字符也出现在数据当中,那么解决方法仍然是在转义字符的前面插入一个转义字符。因此,当接收端收到连续的两个转义字符时,就删除其中前面的一个。下图表示用字节填充法解决透明传输的问题。
现实的通信链路都不会是理想的。这就是说,比特在传输过程中可能会产生差错:1可能会变成0,而0也可能变成1。这就叫作比特差错。比特差错是传输差错中的一种。
在一段时间内,传输错误的比特占所传输比特总数的比率称为误码率BER(Bit Error Rate)。实际的通信链路并非是理想的,它不可能使误码率下降到零。
因此,为了保证数据传输的可靠性,在计算机网络传输数据时,必须采用各种差错检测措施。目前在数据链路层广泛使用了循环冗余检验CRC(Cyclic Redundancy Check)的检错技术。
- 本小节所说的“差错”,如无特殊说明,就是指“比特差错”。
- 误码率为 1 0 − 10 10^{-10} 10−10时,表示平均每传送 1 0 10 10^{10} 1010个比特就会出现一个比特的差错。误码率与信噪比有很大的关系。如果设法提高信噪比,就可以使误码率减小。
下面我们通过一个简单的例子来说明循环冗余检验的原理。
在发送端,先把数据划分为组,假定每组 k k k个比特。现假定待传送的数据 M = 101001 M = 101001 M=101001( k = 6 k = 6 k=6)。CRC运算就是在数据 M M M的后面添加供差错检测用的 n n n位冗余码,然后构成一个帧发送出去,一共发送 k + n k + n k+n位。在所要发送的数据后面增加 n n n位的冗余码,虽然增大了数据传输的开销,但却可以进行差错检测。当传输可能出现差错时,付出这种代价往往是很值得的。
这 n n n位冗余码可用以下方法得出:用二进制的模2运算进行 2 n 2^n 2n乘 M M M的运算,这相当于在 M M M后面添加 n n n个0。得到的 k + n k + n k+n位的数除以收发双方事先商定的长度为 n + 1 n + 1 n+1位的除数 P P P,得出商是 Q Q Q而余数是 R R R( n n n位,比 P P P少一位)。
在下图所示的例子中, M = 101001 M = 101001 M=101001(即 k = 6 k=6 k=6)。假定除数 P = 1101 P= 1101 P=1101(即 n = 3 n = 3 n=3)。经模2除法运算后的结果是:
这种为了进行检错而添加的冗余码常称为帧检验序列FCS(Frame Check Sequence)。因此加上FCS后发送的帧是101001001
(即
2
n
M
+
FCS
2^nM + \text{FCS}
2nM+FCS),共有
k
+
n
k+ n
k+n位。
注意:
- 用模2运算进行加法时不进位,例如,
1111+1010=0101
。减法和加法一样,按加法规则计算。- 循环冗余检验CRC和帧检验序列FCS并不是同一个概念。CRC是一种检错方法,而FCS是添加在数据后面的冗余码,在检错方法上可以选用CRC,但也可不选用CRC。
在接收端把接收到的数据以帧为单位进行CRC检验:把收到的每一个帧都除以同样的除数 P P P(模2运算),然后检查得到的余数 R R R。
101001001
,而除数是
P
=
1101
P=1101
P=1101,看余数
R
R
R是否为0)。总之,在接收端对收到的每一帧经过CRC检验后,有以下两种情况:
一种较方便的方法是用多项式来表示循环冗余检验过程。在上面的例子中,用多项式
P
(
X
)
=
X
3
+
X
2
+
1
P(X) = X^{3}+X^2+1
P(X)=X3+X2+1表示上面的除数
P
=
1101
P= 1101
P=1101 (最高位对应于
X
3
X^3
X3,最低位对应于
X
0
X^0
X0)。多项式
P
(
X
)
P(X)
P(X)称为生成多项式。现在广泛使用的生成多项式
P
(
X
)
P(X)
P(X)有以下几种:
CRC-16
=
X
16
+
X
15
+
X
2
+
1
CRC-CCITT
=
X
16
+
X
12
+
X
5
+
1
CRC-32
=
X
32
+
X
26
+
X
23
+
X
22
+
X
16
+
X
12
+
X
11
+
X
10
+
X
8
+
X
7
+
X
5
+
X
4
+
X
2
+
X
+
1
在数据链路层,发送端帧检验序列FCS的生成和接收端的CRC检验都是用硬件完成的,处理很迅速,因此并不会延误数据的传输。
从以上的讨论不难看出,如果我们在传送数据时不以帧为单位来传送,那么就无法加入冗余码以进行差错检验。因此,如果要在数据链路层进行差错检验,就必须把数据划分为帧,每一帧都加上冗余码,一帧接一帧地传送,然后在接收方逐帧进行差错检验。
最后再强调一下, 在数据链路层若仅仅使用循环冗余检验CRC差错检测技术,则只能做到对帧的无差错接受,即:“凡是接收端数据链路层接受的帧,我们都能以非常接近于1的概率认为这些帧在传输过程中没有产生差错”。接收端丢弃的帧虽然曾收到了,但最终还是因为有差错被丢弃,即没有被接受。以上所述的可以近似地表述为(通常都是这样认为):“凡是接收端数据链路层接受的帧均无差错”。
请注意,我们现在并没有要求数据链路层向网络层提供“可靠传输”的服务。所谓“可靠传输”就是:数据链路层的发送端发送什么,在接收端就收到什么。传输差错可分为两大类:一类就是前面所说的最基本的比特差错;另一类传输差错则更复杂些,这就是收到的帧并没有出现比特差错,但却出现了帧丢失、帧重复或帧失序。例如,发送方连续传送三个帧: [#1]-[#2]-[#3]
。 假定接收端收到的每一个帧都没有比特差错,但却出现下面的几种情况:
[#1]-[#3]
(丢失[#2]
)。[#1]-[#2]-[#2]-[#3]
(收到两个[#2]
)。[#1]-[#3]-[#2]
(后发送的帧反而先到达了接收端,这与一般数据链路层的传输概念不一样)。以上三种情况都属于“出现传输差错”,但都不是这些帧里有“比特差错”。我们应当明确,“无比特差错”与“无传输差错”并不是同样的概念。在数据链路层使用CRC检验,能够实现无比特差错的传输,但这还不是可靠传输。
我们知道,过去OSI的观点是:必须让数据链路层向上提供可靠传输。因此在CRC检错的基础上,增加了帧编号、确认和重传机制。收到正确的帧就要向发送端发送确认。发送端在一定的期限内若没有收到对方的确认,就认为出现了差错,因而就进行重传,直到收到对方的确认为止。这种方法在历史上曾经起到很好的作用。但现在的通信线路的质量已经大大提高了,由通信链路质量不好引起差错的概率已经大大降低。因此,现在互联网就采取了区别对待的方法:
实践证明,这样做可以提高通信效率。