数据链路层
数据链路层主要解决相邻两个节点间的通信问题,它负责将源节点网络层上的数据传输到目的节点的网络层上。所谓相邻是指两个节点通过一条物理信道直接相连。
 
1 数据链路层的设计问题
按照网络的分层模型,每一层都是要利用其下层提供的服务来为其上层提供服务。数据链路层从物理层获得的服务是原始的比特流传输服务,而比特流在传输的过程中是会出错的,因此检测和纠正这些错误使得网络层可以不用关心传输错误,成为数据链路层的一项重要工作。其次较高的发送速度和较低的接收能力的不匹配,也是造成传输出错的一个原因,因此流量控制也是数据链路层的一项重要工作。另外,不同的应用或者传输环境可能要求不同的链路层服务,因此链路层应该有多种服务供上层选择,且每种服务有定义良好的接口供上层调用。
综上所述,数据链路层的主要功能(或者说主要设计问题)包括以下三个方面:
l          为网络层提供良定义的服务接口;
l          处理传输错误;
l          流量控制。
 
服务类型
可以让数据链路层提供多种不同的服务,但大多提供以下三种服务:
l          无确认的无连接服务:源节点向目的节点发送独立的帧,传输前不需要建立逻辑连接,传输后也不要求目的节点进行确认,也就是说不保证每个帧能被正确接收。目的节点可能会将出错的帧丢弃,但不会通知源节点,也不会试图发现是否有帧丢失,传输错误的恢复依靠高层协议去完成。这类服务适用于误码率非常低的传输环境及一些实时业务,大多数局域网使用这一类服务。
l          有确认的无连接服务:传输前不需要建立逻辑连接,但目的节点对于收到的每个帧都必须单独进行确认(肯定或否定),出错或丢失的帧需要重发,直到正确接收为止。这类服务适用于误码率较高的传输环境,如无线传输环境。(事实上,要求确认在这儿是一种优化传输服务的选项,而不是必需的。)
l          有确认的面向连接的服务:传输前需要建立逻辑连接,为每个发送的帧建立帧编号并按序发送,目的节点对收到的帧进行检错和确认,出错或丢失的帧需要重发直至正确接收为止,目的节点的链路层保证向其网络层递交正确有序的数据流。
 
组帧
       我们考察四种方法
l         字符计数法:在帧的第一个字段携带帧的长度。这种方法在帧传输出错后无法恢复同步,因此不能单独使用。
l         带有字节填充的标志字节法:使用特殊的字节(标志字节)来表示帧的开始与结束,当失去同步后,只需要搜索特定的标志字节就可以了。为避免在帧的其它部分出现与标志字节相同的比特模式,采用了字节填充的方法,即在与特殊字符具有相同比特模式的字符前插入转义字符ESC。这种方法要依赖于特定的字符编码集,灵活性差,处理开销大。
l         带有比特填充的起止标志法:使用一个特殊的比特模式(01111110)作为帧的起始与结束标志。为避免在帧的其它部分出现与此标志相同的比特模式,采用了比特填充的方法,即在5个连续的1后插入一个0。这种方法不依赖于特定的字符编码集,灵活性强,处理简单(使用硬件完成)。
l         物理层编码违例法:这种方法只适用于那些在物理层编码中使用冗余技术的网络,例如以太网的物理层采用曼彻斯特编码,它将比特“1”表示成高-低电平对,将比特“0”表示成低-高电平对,而高-高电平对和低-低电平对在编码中没有使用,这样可以用这两种无效的编码标识帧的边界。
 
差错控制
       差错控制的主要内容包括:差错编码、反馈重传、超时重传、重复帧丢弃、定时器管理等。
 
流量控制
       基于反馈的流量控制机制。
 
2. 差错检测与纠正
出错的类型:单个错(single error)与突发错(burst error)。单个错通常由随机的信道热噪声引起,一次只影响1位,错误之间没有关联。突发错通常由瞬间的脉冲噪声引起,一次影响许多位,用突发长度表示突发错影响的最大数据位数。在实际的通信中,经常发生的错误是突发错。突发错有利于数据传输,但不利于检测和纠正。
 
       差错编码的类型:检错码(error-detecting code)与纠错码(error-correcting code)。检错码只能检测到数据传输发生了错误,但不知道错在哪一位上,因此无法自行纠正错误,需要与反馈重传结合起来使用。纠错码能够知道错误发生在哪一位上,因此能够自行纠正错误。当信道条件允许时,通常采用检错码与反馈重传来检测和纠正错误。
 
如何检测和纠正错误?
       长度为m比特的数据(或称消息)加上r比特的冗余(或称校验位)形成长度为n=m+r比特的码字(codeword)。两个码字的不同位的个数称为这两个码字之间的海明距离dHamming Distance),它意味着需要d个位的错误才有可能使一个码字变为另一个码字。在大多数传输应用中,所有2m个可能的数据信息都是有效的,当计算校验位的方法确定后,就可以构造出完整的有效码字表(共2m个有效码字)。但长度为n的码字集中共有2n个码字,显然其中2n-2m个码字是无效的,它们只可能在传输发生错误时出现。因此,判断是否出现传输错误的方法就是判断收到的码字是否是无效码字,而纠错码纠正错误的方法就是将收到的无效码字恢复到距其最近的有效码字,显然任何检错和纠错的方法都有一定的漏检概率。
 
编码集的检错与纠错能力
       编码集的海明距离:编码集中任意两个有效码字间的海明距离的最小值。
编码集的检错和纠错能力与编码集的海明距离有关。为检测出d比特错误,编码集的海明距离至少应为d+1,奇偶校验是能够检测出1比特错误的检错码。为纠正d比特错误,编码集的海明距离至少应为2d+1,海明码是能够纠正1比特错误的纠错码。
 
循环冗余码(CRC码)
       这是一种多项式编码,它将位串看成是系数为01的多项式。
       信息多项式M(x)m个信息比特为系数构成的多项式。
       冗余多项式R(x):由r个冗余比特为系数构成的多项式。
       码多项式T(x):在m个信息比特后加上r个冗余比特构成的码字所对应的多项式,表达式为:T(x) = xr·M(x) + R(x)
       生成多项式G(x):双方预先确定用来计算R(x)的一个多项式。
       编码方法:用对应于G(x)的位串去除对应于xr·M(x)的位串,所得的余数附加到信息比特串的后面一起发送。
       检错方法:用对应于G(x)的位串去除对应于T(x)的位串,若余数为0则认为传输正确,否则认为传输错误。
       CRC码检错能力强,实现简单快捷,是应用最广泛的检错码。
 
3. 基本数据链路协议
       通过三个由简单到复杂的数据链路协议来介绍该层协议的基本设计思想。在这里假设源主机A与目的主机B通过一条单工信道进行通信,且A使用可靠的面向连接的服务向B传输数据。
A的数据链路层收到网络层的一个分组后,将其嵌入到一个数据帧中,即加上帧头(控制信息)和帧尾(校验),然后传给B的数据链路层。假设数据链路层可以通过库例程 to_physical_layerfrom_physical_layer/从物理层发送/接收帧,且校验部分(帧尾)由发送硬件自动加上和校验,链路层软件可不用关心。数据链路层还可以通过库例程 to_network_layerfrom_network_layer/从网络层发送/接收分组。数据链路层调用库例程wait_for_event (&event)等待某个事件的发生,事件的类型从变量event中获得。假设帧头包括类型、发送序号、确认序号三个域(仅为示例用)。
 
协议1
       这是一个最简单的单工协议,假设数据只在一个方向上传输,信道不会出错,且网络层和物理层始终处于准备好状态,因此既不需要差错控制也不需要流量控制。过程如下:
       发送方                                                     接收方
1)      从网络层接收一个分组;                   1) 等待帧到达事件;
2)      将分组装入帧的信息域;                   2) 从物理层接收一个帧;
3)      将帧传给物理层;                             3) 将分组(帧的信息域)传给网络层;
4)      返回 1)                                             4) 返回 1)
由于不需要确认,也就不需要帧序号。
 
协议2
       仍然假定是单工通信,且信道不会出错,但是接收端的处理能力有限,需要控制发送方的速度,即流量控制。在这里需要引入反馈,要求接收端在准备好接收下一帧时,向发送方发回一个响应帧;而发送方在收到响应帧后,才能发送下一帧,这称为停-等。过程如下:
       发送方                                                     接收方
1)      从网络层接收一个分组;                   1) 等待帧到达事件;
2)      将分组装入帧的信息域;                   2) 从物理层接收一个帧;
3)      将帧传给物理层;                             3) 将分组(帧的信息域)传给网络层;
4)      等待响应帧;                                    4) 发送响应帧;
5)      响应帧到达,返回 1)                        5) 返回 1)
       由于每次只发送一个帧,得到响应后再发下一帧,且不会出错,因此不会有重发的需要,也就不需要帧序号。
 
协议3
       仍然假定是单工通信,但是信道可能会出错,接收端处理能力也有限。链路层必须保证每个帧正确到达接收端,且发送端不能以太快的速度发送,因此,在这里既需要差错控制也需要流量控制。
采用协议2中的停-等方式,发送方每次只发送一个帧,当这个帧被正确接收后才能发送下一帧,若该帧未在规定的时间内得到确认(超时),则重发该帧;接收端对每个收到的帧进行校验,对正确收到的帧发回确认,错误的帧丢弃。由于需要区分新、旧两个帧,使用1比特的帧序号。过程如下:
       发送方
1)    初始化发送序号(next_frame_to_send = 0);
2)    从网络层接收一个分组,放入缓冲区;
3)    从缓冲区中取出分组构造一个帧:
l         将缓冲区中的分组拷入帧的信息域;
l         next_frame_to_send拷入序号域;
4)    将帧传给物理层;
5)    启动相关的计时器;
6)    等待事件发生(帧到达,收到坏帧,超时);
7)    事件发生:
     事件为帧到达:从物理层接收一个帧,检查帧的确认序号域,
l          若是对所发帧的确认(ack = next_frame_to_send),终止相关的计时器,从网络层接收下一个分组,放入缓冲区,发送序号加1,返回 3)
l          若不是对所发帧的确认,直接返回 3);(缓冲区内容和发送序号均不变)
     事件为其它(收到坏帧,超时):返回 3);(缓冲区内容和发送序号均不变)
 
接收方
1)    初始化期待接收的帧序号(frame_expected = 0);
2)    等待帧的到达;
3)    从物理层接收一个帧,检查帧的发送序号域(seq),
l          如果是期待接收的帧(seq = frame_expected),将帧中携带的分组交给网络层,frame_expected1,执行4);
l          若不是期待接收的帧(一个重复帧),执行4);
4)    发回对收到帧的确认(确认帧的ack等于收到帧的seq);
5)    返回 2)
 
4. 滑动窗口协议
       前面的协议都假定数据帧沿着一个方向传输,但事实上大多数的通信都是双向的。当双方都有数据发送时,将确认序号携带在数据帧中传输可以减少开销,这称为捎带应答(piggybacking)。捎带应答带来的一个问题是,当需要发送确认时没有要发送的数据帧怎么办?这可以让确认信息推迟一点时间再发送,如果仍然没有数据帧要发送,再用一个单独的帧进行确认。    以下三个协议都是用于双向数据传输的协议,且都属于滑动窗口协议,但它们的效率、复杂度及对内存的需求都不同。
在滑动窗口协议中,每一个要发送的帧都包含一个序号,范围是从0到某个最大值,最大值通常是2n-1n为帧序号的长度。滑动窗口协议的要点是,任何时刻发送进程要维护一组帧序号,对应于一组已经发送但尚未被确认的帧,这些帧称为落在发送窗口内;类似地,接收进程也要维护一组帧序号,对应于一组允许接收的帧,这些帧称为落在接收窗口内。
       发送窗口中的序号代表已发送但尚未确认的帧,其中窗口下沿代表最早发送但至今尚未确认的帧。当发送窗口尚未达到最大值时,可以从网络层接收一个新的分组,然后将窗口上沿加1,并将新的上沿序号分配给新的帧;当收到对窗口下沿帧的确认时,窗口下沿加1。由于每一个帧都有可能传输出错,所以发送窗口中的帧都必须保留在缓冲区里以备重传,直至收到确认为止。当发送窗口达到最大值时,停止从网络层接收数据,直到有一个缓冲区空出来为止。
       接收窗口中的序号代表允许接收的帧,任何落在窗口外的帧都被丢弃,落在窗口内的帧存放到缓冲区里。当收到窗口下沿帧时,将其交给网络层,并产生一个确认,然后窗口整体向前移动一个位置。和发送窗口不同,接收窗口的大小是不变的,总是保持初始时的大小。接收窗口大小为1,意味着数据链路层只能顺序接收数据,当接收窗口大于1时不是这样,但无论如何,数据链路层必须按顺序将数据递交给网络层。
       1位滑动窗口协议
       该协议使用停-等方式,所以只需要1比特长的帧序号。帧头中至少包括seqack两个域,ack用于对正确收到的帧的序号进行确认。由于支持双向传输,所以每个协议实体需要同时完成发送和接收两个功能。过程如下:
1)    初始化发送序号和期待接收的帧序号:next_frame_to_send = 0frame_expected = 0
2)    从网络层接收一个分组,放入缓冲区;
3)    从缓冲区中取出分组构造一个帧:
l         将缓冲区中的分组拷入帧的信息域;
l         next_frame_to_send拷入发送序号(seq)域;
l         1- frame_expected拷入确认序号(ack)域;(初始化后双方发送的第一个帧的序号均为0,而该实体在发送第一个帧时尚未收到另一方发来的帧0,所以ack域必须为1
4)    将帧传给物理层;
5)    启动相关的计时器;
6)    等待事件发生(帧到达,收到坏帧,超时);
7)    事件发生:
     事件为帧到达:从物理层接收一个帧,
a)    检查帧的seq域,若正是期待接收的帧(seq = frame_expected),将帧中携带的分组交给网络层,frame_expected1,继续 b);(作为接收实体的处理,若不是期待接收的帧,frame_expected不变)
b)    检查帧的ack域,若是等待确认的帧(ack = next_frame_to_send),终止相关的计时器,从网络层接收一个新的分组放入缓冲区,next_frame_to_send1,到 8);(作为发送实体的处理,若不是等待确认的帧,缓冲区内容及next_frame_to_send均不变)
     其它事件(收到坏帧,超时):到 8);(缓冲区内容及两个序号变量均没变)
8)    用缓冲区中的分组、next_frame_to_send1- frame_expected构造一个帧;
9)    传给物理层;
10)  启动计时器;
11)  回到 6)。
在正常情况下,发送方和接收方交替发送;但当发送方和接收方同时向对方发送,或超时设置得太短时,会造成不必要的重发,但协议也能够正常运行。
 
Go Back N
       直到现在,我们一直假定信号的传播延迟可以忽略不计,但事实上有些时候是不能忽略的,比如在卫星信道上(例)。如果信道的数据速率为b bit/s,帧的长度为L bits,信号的来回延迟为R秒,则线路的效率为Lb/(L+bR)。如果我们在等待确认的时候多发送一些帧,就可以提高线路的效率,这事实上允许发送窗口包含多个未被确认的帧,这种技术称为管道化(pipelining)。当信号传播延迟远大于帧的传输时间时,适合采用这个技术。
       当管道化技术建立在不可靠的信道上时会有一些问题。比如,如果位于帧流中的某个帧丢失或损坏了,会发生什么情况?在发送进程发现出错前,大量的后继帧会到达接收方;当一个坏帧到达接收方时,显然会被接收方丢弃,那么后面到来的帧如何处理?
       有两种基本的方法来处理以上问题,一种方法称为go back n,接收进程丢弃所有的后继帧,并且不通知发送进程。该策略对应接收窗口为1的情况,即只能按顺序接收帧,当发送进程超时后,必须按顺序重传所有未被确认的帧。如果错误率高的话,这种方法会浪费很多带宽,但对内存需求不大。
       另一种方法称为选择重传(对应接收窗口大于1的情况),只要是落入接收窗口且校验正确的帧,都要接收下来放到缓冲区里,这样当发送进程意识到某个帧出错时,只是重传此帧而不是所有的后继帧。选择重传通常使用NAK对校验出错或疑为丢失的帧进行确认,以便发送进程尽快重传该帧。如果第二次重传成功,接收方的数据链路层中会有许多按顺序排列的正确帧,这些帧可以一起交给网络层,并只对最高序号的帧进行确认。当窗口很大时,这种方法需要大量的数据链路层内存,但它不浪费带宽。
       Go back n的过程如下:
1)    初始化:
l         开网络层允许;
l         ack_expected = 0;(发送窗口下沿)
l         next_frame_to_send = 0frame_expected = 0
l         nbuffered = 0;(发送窗口大小)
2)    等待事件发生(网络层准备好,帧到达,收到坏帧,超时);
3)    事件发生:
    事件为网络层准备好:
l         从网络层接收一个分组,放入相应的缓冲区;
l         发送窗口大小加1
l         使用缓冲区中的分组、next_frame_to_sendframe_expected构造帧,发送;(ack中的值表示该序号及该序号之前所有的帧已全部正确收到)
l         next_frame_to_send1
l         跳转4)
    事件为帧到达:从物理层接收一个帧,
a)    检查帧的seq域,若正是期待接收的帧(seq = frame_expected),将帧中携带的分组交给网络层,frame_expected1(修改接收窗口),继续 b)
b)    检查帧的ack域,若ack落于发送窗口内,表明该序号及其之前所有序号的帧均已正确收到,因此终止这些帧的计时器,修改发送窗口大小及发送窗口下沿值,将这些帧去掉;(用一个while循环来完成)
c)    跳转 4)
    事件是收到坏帧:跳转 4)
    事件是超时:next_frame_to_send = ack_expected,从发生超时的帧开始重发发送窗口内的所有帧,然后执行 4);
4)    若发送窗口大小小于所允许的最大值(MAX-SEQ),开网络层允许,否则关网络层允许;(判断发送窗口是否达到最大值)
5)    返回 2)
这个协议有一个问题,没有考虑到当某个方向上没有数据要发送时,要对收到的帧进行单独确认。在收到期待的帧后应该启动一个ACK超时计时器,当发生超时事件时,判断哪个计时器超时,若是ACK计时器超时,应该单独发送一个确认帧。而当发送了一个数据包时,应将被捎带确认的帧的ACK计时器终止。
       使用go back n协议,发送窗口的大小不能超过2n-1。用书上的例子解释。
 
选择性重传
       在该协议中,发送方的窗口大小从0开始增长到某个预定的最大值,而接收方的窗口总是保持固定大小并等于该最大值。接收窗口内的每个序号都有一个缓冲区,并有一位指示缓冲区是空还是满。当一个帧到达时,只要其序号落在接收窗口内且此前并未收到过(相应缓冲区为空),就接受此帧并存于相应的缓冲区中;仅当序号比它小的所有帧都已递交给了网络层,此帧才会被提交给网络层。
       选择重传的过程如下:
1)    初始化:类似go back n的初始化,但增加了与接收窗口相关的内容,如设定接收窗口的大小、清空缓冲区满标志等;
2)    等待事件发生(帧到达,收到坏帧,数据帧超时,网络层准备好,ACK超时);
3)    事件发生:
    事件为网络层准备好:从网络层接收一个分组,组帧发送,修改相关参数,与go back n的处理同;跳转到 4)
    事件为帧到达:从物理层接收一个帧,
a)    若为数据帧,
i)    若不是期待接收的帧且未发送过NAK,则发送一个NAK帧,要求重发指定序号的帧(frame_expected);否则启动ACK计时器;继续 ii)
ii)   若收到的帧落在接收窗口内且此前未收到过,则放入相应缓冲区并设置缓冲区满标志;继续 iii)
iii) 若接收窗口下沿帧已经到达,则从该帧开始将连续的若干个帧交给网络层,并修改相应参数(缓冲区满标志,接收窗口范围),启动ACK计时器;跳转到 c)
b)    若为NAK帧,且请求重发的帧落在当前的发送窗口内,则重发这个帧;
c)    若从发送窗口下沿开始连续的若干个帧已被确认,则终止这些帧的计时器,修改发送窗口大小及发送窗口下沿值将这些帧去掉;跳转到 4)
    事件为收到坏帧:如果尚未发送过NAK,则发送一个NAK;跳转到 4)
    事件为超时(数据帧超时):重发超时的帧;跳转到 4)
    事件为ACK超时:为指定的帧发送单独的确认帧;跳转到 4)
4)    若发送窗口大小小于所允许的最大值(NR_BUFS),开网络层允许,否则关网络层允许;
5)    返回 2)。
使用选择重发协议,发送窗口不能大于2n-1。用书上的例子说明。
 
5. 数据链路协议举例
 
HDLC
       这是ISO颁布的一个面向比特的全双工数据链路协议。
帧格式除标志外包括地址、控制、信息和校验和几个部分,其中信息部分可以没有,因此有效帧长度至少为32比特。
l         帧标志:01111110,用于表示帧的边界,也用于帧间填充。使用比特填充保证数据的透明传输。
l         地址:在点-多点线路(多终端)中用于区分各个终端,而在点-点线路中用于区分命令和响应。
l         控制:用于构成各种命令与响应,是HDLC的关键。
l         信息:可以包含任何信息,原则上没有长度限制。
l         校验和:CRC编码。
l          
帧的类型:信息帧、监控帧和无编号帧。
l         信息帧:用于携带数据;
l         监控帧:用于差错控制和流量控制;
l         无编号帧:用于链路管理。
 
这三种帧的控制字段如下。协议采用滑动窗口机制,使用3比特帧序号。
l         seq:帧序号;
l         next:下一个期待接收的帧序号;
l         P/F:探询/终止位,有多种用途,在点-多点线路中可用于选择一个终端,在有些协议中可由发送站用来要求接收站立即发送一个监控帧,还有其它一些用途。
l         type:决定监控帧的类型:
类型0RECEIVE READY):肯定性确认帧,用来指示下一个希望收到的帧,当没有用于捎带的反向传输时使用此帧。
类型1REJECT):否定性确认帧,要求从next域所指示的序号开始重发此后所有的帧。
类型2RECEIVE NOT READY):确认直到(不包括)next的所有帧,但要求发送方暂停发送。
类型3SELECTIVE REJECT):要求重传next域指定的帧。有些协议没有这类帧。
l         modifier5个修正位可以构成最多32种链路命令和响应(无编号帧),事实上没有用到这么多。常见的命令或响应有:断开连接、置链路模式、帧拒绝、无编号响应、无编号数据等。
      
Internet中的点-点数据链路层协议
       Internet中有很多地方需要用到点-点线路,如大量家庭用户使用拨号线路上网、集团用户使用租用线路将局域网连到因特网上,而通信子网中的路由器与路由器之间几乎都采用专线(特别是光纤)进行互连。在这些点-点线路上,需要某种数据链路层协议完成成帧、差错控制和流量控制等功能。
 
PPP
       PPP是因特网中广泛使用的一种点-点数据链路协议,它有检错能力、支持多种网络层协议、支持IP地址的动态分配、支持身份认证等多种功能。PPP有以下三个主要特色:
l         提供一种组帧的方法用于区分帧的边界,并可支持差错检测;
l         提供一种链路控制协议,用于链路的建立、测试、协商及拆除;
l         提供一组网络控制协议,用于支持多种网络层协议;特别是支持IPNCP支持IP地址的动态分配。
使用PPP通信的过程:
l         首先在两个modem之间建立物理连接;
l         然后使用LCP建立链路;
l         然后使用NCP配置网络层,特别是支持IPNCP会向ISP申请分配一个IP地址;
l         这时PC就在Internet上了;
l         完成工作后首先使用NCP拆除网络层连接,释放IP地址;
l         然后使用LCP关闭数据链路层连接;
l         最后释放物理连接。
PPP的帧格式与HDLC很相似,但有几点不同:
l         PPP是面向字符的,因此为实现透明的数据传输采用的是字符填充技术,且帧长都是字节的整数倍;但PPP也能在面向比特的线路上使用。
l         地址总是设成11111111,以免去数据链路地址的分配。
l         控制缺省为00000011,即缺省时采用不可靠无编号的数据传输方式,但需要时也可以协商采用可靠的有编号的数据传输方式;
l         增加了协议域,用于指出载荷字段中携带的是哪类分组,从而可以支持LCPNCP及不同的网络层协议;
l         许多字段的长度是可以协商的,而且支持头部压缩。
总之,PPP是一个适合于运行在modem拨号线路、HDLC比特串行线路、SONET和其它物理层上并支持多种网络层协议的数据链路层协议,它支持错误检测、选项商定、头部压缩及可靠与不可靠的数据传输服务。