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