数据链路层-Data Link Layer:拆分比特流的成帧方法/滑动窗口协议/回退N协议/选择重传协议
第三章 数据链路层-Data Link Layer
3.1数据链路层概述
数据链路层是我们接触到的第一个网络层次,同时也广泛的存在于我们的生活中。由于一些同学会在学习过程中把不同网络层次的内容搞混,所以我觉得有必要先对数据链路层做一个整体的描述:数据链路层所考虑的内容只与本地节点之间的数据交付(local delivery of frames)有关。换句话说,单个数据帧不会超出局域网的范畴(数据帧是链路层的一个传输单元),而所谓“节点”,可能只是一台本地机器,也可能是一个连接到了网络层的设备,或者是一个集线器,把数据连向另外一个本地网络。
数据链路层使用物理层提供的服务,在通信信道上发送和接收比特。它的主要任务是将一个传输设施转变成一条没有漏检传输错误的线路。发送方需要将网络层的数据拆分成数据帧,然后按照顺序发送他们。一个数据帧可能会有几百到几千个字节长度。在实现自己目标的过程中,可能会遇到各种各样的问题(比如信道占用、数据传输出错、接收方数据处理能力太低...等等)。为了保证这些比特流成功的发送到链路的接收方,链路层需要考虑设计一种合适的帧结构以拆分数据,一个合适的流量控制系统防止发送端的数据淹没接收方,一个纠错或者验错系统发现并解决传输中的错误,以及一种决定谁来发送数据的协议(这一部分会在第四章中展开)。
下面对数据链路层做一个简单的刻画,读者可以通过链路层的功能和提供给上层的服务来认识这一层。
3.1.1主要功能:
- 为网络层提供接口
- 通过单个链路传输数据帧(frame),其中包括以下两个功能:
- 处理错误handle errors
- 调节数据流 Regulate flow data
3.1.2 提供给网络层的服务
- 无确认无连接的网络(802.3如以太网)
- 有确认无连接的网络(如802.11无线局域网)
- 有确认有链接的网络(如卫星信道、无线电话)
3.2 成帧方法
前面已经说到,数据链路层通过发送数据帧进行交互。下面具体讲解一些数据链路层中帧的结构,以及通过这些特殊设计的结构,数据链路层可以提供的服务(尤其指纠错与验错)。
3.2.1数据链路层帧的结构
数据链路层将网络层的数据包(packet)封装进一个帧(frame)里。这个过程通过给包添加帧头和帧尾来实现,如下图。
3.2.2成帧
当数据在电线中进行传输时,必须被分成可辨识的数据块。因此,需要接收器和发送器达成一种共识,明确发送的一连串二进制数据中,有哪些属于同一个帧。这部分的内容即是针对这个问题展开的。这些方法总称为拆分比特流的成帧方法:
1-字节计数法(Byte Count)
可见,在每个frame前面,都会添加一个字节的数据来存储本帧大小。接受方接收到第一个字节,便可以得知这一帧的范围。这么做的问题在于,一旦关键字节传输错误(这种情况在不稳定的连接中有可能发生),后面的数据都存在识别错误的风险。
2-字节填充法(Byte Stuffing)
基于此,人们进行了一些改进。现在不再通过帧头计数的方法区分不同的帧,而是使用一个特定无实际含义的标志来作为帧和帧的边界(在这种方法中,同样是一字节大小)。但是这么一来,由于原始数据中很可能出现同标志FLAG一样的字节,很有可能产生歧义,因此需要很复杂的转义操作。(想想c语言中的转义符号)
上图中,转义字节是ESC,标志字节是FLAG。如果原数据中就有FLAG,那么需要在FLAG前加上ESC;而如果原数据本来包含ESC FLAG,就需要在这两个字节前面都加上ESC...这个问题可以一直递归下去。(狗头
3-位填充(Bit Stuffing)
位填充的思路和之前的字节填充类似,但是这次增加的不再是比特位,而是以6个连续的1作为标志;至于之前的转义问题,则使用了另一种巧妙的方法解决:
在发送时,机器每遇到5个连续的1,就会在后面添加一个0。相对应的,接受时,每遇到5个1就会去掉后面的一个0。这样一来,6个连续的1可以很好的标记出帧的边界。
4- 三种方式的优缺点如下:
字节计数 | 在每一个帧前面设置一个计数器,记录该帧里面一共有多少字节 | 当然这种方式并不可靠,其问题在于:计数值可能因为一个传输错误而弄混 |
字节填充 | 用特殊的标志字符(字节)来界定帧,如,这个字符可以是01111110这个字节(同时,为了防止与原始数据中的内容冲突,可能需要对原数据进行转义。转义时,在原数据对应字节前加上一个ESC) | 使用转义符的方法的确解决了原数据种含有冲突内容的情况,但是因为ESC同样也是一个字节,在原数据中出现时也有可能出现混淆的情况,比较麻烦。 |
位填充(主流!) | 帧标志由6个连续的1组成;在传输是,每有5个连续的1,就在后面添加一个0;在接受的时候,每有5个连续的1,就把后面的0删除 | 保证了透明传输:数据中的任意组合不引起帧边界判断失误 |
3.2.3 差错控制&流量控制
这个子标题中,我们先对差错控制与流量控制建立起一个基础的概念,之后再详细展开。
差错控制的目的在于确保传递的可靠性。然而实际情况总是很复杂的,需要一个方法应对数据帧丢失、错误、冗余等等问题。数据链路层引入了计时器和序号来解决这个问题;而流量控制,顾名思义,就是对传送中的数据的流量进行控制,通过特定的协议选择一个合适的收发速率,以使接收方有足够的缓存空间来接受每个帧。流量控制的方法大体分为两种,一种是基于反馈的流量控制,另一种是基于速率的流量控制。前者要求接收方发送消息,来确认接收方的状态(如发送是否过快,等等);后者通过协议内置的机制直接限制发送方的发送速率。本章将学习基于反馈的流控方案。
3.3 检错与纠错
下面讲一下数据链路层怎么发现错误。在物理层的传输过程中,总有可能出现传输错误或丢失的情况。链路层有两种错误的应对策略。两种方式都在原帧中插入冗余信息,其中一种使用纠错码,使得接收方可以推断出原先的内容;后一种使用验错码,使得接收方可以知道传输出错,从而提醒发送方重新发送。
- 总体上,都使用了增加冗余信息的方法
- 纠错码:海明码,二进制卷积码,里德所罗门码,低密度奇偶校验码
- 验错码:奇偶,校验和,循环冗余校验(CRC)
3.4 数据链路层经典协议
在这个子标题中,我们继续谈论一些好玩的东西。
3.4.1 三种经典协议(单工)
下面从简单情况下开始,讨论几种经典的传输协议。以下的几种协议讨论的全部是单工式的,所谓单工,指的是数据只能在通信信道上单项传输。同理,还有双工和半双工两种模式,指的分别是:数据在某一信道上可以同时沿两个方向发送和是指数据可以沿两个方向传送,但同一时刻一个信道只允许单方向传送
一个乌托邦式的单工协议
之所以称为乌托邦式,就是因为这个协议讨论的情况十分理想,来看看它的成立条件:
- 不考虑数据传输出错(通信不会丢失或者损坏帧)
- 数据只能单向传播(单工!)
- 可用的缓存无限大,不考虑数据处理时间
在这种情况下,发送端只需要直接发送数据即可,不需要考虑多余的因素。尽管以上三个条件不太可能出现在现实应用中,但乌托邦式协议的贡献在于提供了一种协议的基础,我们可以在此基础上一步一步的做一些改进。
无错信道上的单工停-等式协议
这一回我们将考虑数据传输的问题。假如发送方的发送速度高于接受方的速度,接收方将很快被数据淹没。所以在这个协议中,最明显的区别是加入了停-等的概念(stop and wait)。即:发送方每发送一帧,都会停下来等待接收方的确认。收到确认后才会继续发送新的信息。
有错信道上的单工停-等协议
既然发送的帧有可能会出错或者丢失,那么就需要一种机制可以有效地对传送失败的内容进行重传。
一方面,为了防止传输数据丢失而接收方还在等待的情况发生,我们引入了计数器来解决这一问题。
另一方面,我们引入自动重复请求(Automatic Repeat reQuest),使得发送方在发送下一个数据前,必须等待一个肯定的确认。
3.4.2滑动窗口协议(Sliding Window Protocol)
在以下的部分中,我们将去掉原先单工信道的预设。这一部分中,一条链路可以传输两个方向的数据。
在这种情况下,我们可以通过捎带确认的方法优化我们的协议。
- 稍待确认:接收方暂时延缓确认,取而代之的,让确认消息搭载在下一个出境的数据帧上的技术。
所有的滑动窗口本质是,在任何时刻,发送方总是维持着一组序号,分别对应于允许它发送的帧。这些帧落在发送窗口内。类似的,接收方也维持着一个类似的接收窗口对应着一组允许它接受的帧。
下面这张图片可以帮助各位看官加深理解。
1位滑动窗口协议
一位滑动窗口协议是滑动窗口协议中最基础的一个协议。在这个情况下,接收方和发送方的窗口大小均为1。
下图描述了一个典型的一位滑动窗口协议。协议可能出现的问题在于,当A和B同时发起通信,每一帧都会被多次重复发送,严重浪费了带宽。
回退N协议(Go Back 'N')
在这个协议中我们将考虑一些更加复杂的情况。这里,帧在链路上的传输时间也会被纳入考虑范围。既然每一个帧都会花费相当多时间在链路上传输,那么接收方应当更加合理的利用这段时间,达到更高的传输效率。一种解决技术被称为管道化。
管道化:保持多个帧同时在传送的技术。
那么接收方和发送方应当使用什么样的技术以保证一个最大化的数据传输速度呢?回退N协议解决的正是这个问题,见下图:
图:数据丢失后丢掉后续所有帧
可见,在GBN协议中,接收窗口大小是1,当出现了传输错误或者丢包的情况后,接收方便会简单的丢弃所有后续到达的帧,并向发送方发送一个NAK否定确认。发送方会重新发送出错的帧及其后所有的帧。
读者请注意,GBN协议是基于滑动窗口的,但它不再属于停-等式协议。GBN协议有着不错的传输效率,但是假如网络状况很差,GBN将会导致大量的数据重新发送,其效率可能反而不如停-等式。而之所以会出现这样的情况,就是因为数据帧在链路中传播的延迟问题。
选择重传协议(Selective Repeat )
在选择重传协议中,接收窗口大于1。但区别于GBN中直接丢弃所有帧,在SR中接收方只丢弃掉坏的帧,仍会接受之后好的帧。见下图:
至此,数据链路层的主要协议已经描述完毕,请读者移步下一章: 第四章 介质访问控制子层