窥探数据链路层可靠传输:停止-等待、回退N帧和选择重传对比

851 阅读15分钟

📣 大家好,我是Zhan,一名个人练习时长一年半的大二后台练习生 🖥️

📣 这篇文章是 深入浅出计算机网络 第三篇笔记📙

📣 如果有不对的地方,欢迎各位指正🙏🏼

📣 与君同舟渡,达岸各自归🌊


🔔 引语

在上篇文章中 物理层的比特流是怎么进行传输的呢?,我们了解到了:物理层来传输比特流的,但是比特流是无法进行直接进行传输的,而是需要数据链路层来控制这些数据的协议

这里首先说明几个概念:

  • 链路:也就是相邻结点的物理线路,其实其实我们上篇文章讲到的物理层
  • 数据链路:要在链路上传输数据,仅仅有物理层是不够的,还需要一些通信协议来控制这些数据的传输,如果把这些协议的硬件和软件加在链路上,就构成了数据链路
  • :在数据链路上,帧是传输和处理数据的单位,也就是说传输的信息就是一个帧一个帧的传输

那么物理层的比特流,如何封装成帧、在传输的过程中误码差错如何解决,又怎么保证可靠的传输,这都是本文会去讲解的问题:


一、封装成帧

封装成帧,其实就是把网络层交付下来的协议数据单元添加一个首部和一个尾部,让它成为一个

那么帧的尾部和首部都有哪些信息呢?

由于不同帧所实现的协议是不一样的,因此不同的帧的尾部和首部的信息是不太一样的,例如 MAC帧PPP帧

  • MAC 帧 的帧头和帧尾组成为:目标地址、源地址、类型、FCS(下文中的循环冗余校验)

  • PPP 帧 的帧头和帧尾组成为:标志(下文中的定界符)、地址、控制、协议、FCS,其中控制、地址这两个是暂留的,没有实际作用

在数据链路层,他们都需要解决一个问题:接收方的数据链路层如何从物理层交付上来的比特流提取出一个个的帧? 或者说一串比特流中,我们如何判断哪些部分是一个帧,而我们上述提到的两种协议的帧的实现方式并不一样:

PPP帧的实现方式

对于PPP帧来说,帧头和帧尾的作用之一就是帧定界,也就是标识一个帧的开始和一个帧结束的标志,我们可以发现PPP帧中的两个一字节的标志位,分别用于标识帧的开始和结束:

  • 那么如果数据负载里面出现了和标志符一样的字节,就会导致误判,因此引入了转义字符,在发送帧之前对其进行扫描,每发现一个和帧定界符一样的就在其前面加上一个转义字符
  • 如果数据单元中同时拥有帧定界符和转义字符,就会每发现一个转义字符也会加上转义字符 这样就可以实现透明传输
  • 透明传输:数据链路层对上层交付的传输数据没有任何限制,也就是说无论上层交付任何数据都能传输

MAC帧的实现方式

但是在 MAC 帧实现的以太网协议中,我们观察 MAC 帧的帧头和帧尾,并没有发现标志,也就是定界符

  • MAC帧的开始:它会在物理层加上一个八字节的前导码,前导码的前七个字节是用于同步时钟,最后一个字节是表示 MAC 帧的开始
  • MAC帧的结束:同时以太网还规定了 96比特 的发送时间,也就是说发送完一帧后,发送下一帧的时间是经过 96 比特时间,因此 MAC 帧并不需要帧结束定界符

二、差错检测

实际的通信链路都不是理想的,也就是说比特流在传输的过程中可能出现差错:0变成1,因此我们需要检测出是否有差错,这里就会使用到差错检测码,也就是我们在帧的结构中看到的 FCS

下面是两种进行差错检测的方式:


1. 奇偶校验:在待发送的数据后面加上一位奇偶校验位,代表整个数据中“1”的个数是奇数还是偶数

  • 优势 很明显,它只占了一个比特的空间,所占的空间很小
  • 缺点 也很明显,如果出现偶数个误码,就无法进行校验,不难看出它的漏检率很高

2. CRC 循环冗余校验

  1. 双方约定好一个生成多项式
  2. 发送方基于待发送的数据和生成多项式计算出冗余码
  3. 接收方通过生成多项式来计算收到的数据是否产生了误码

听起来可能不太能理解,我们举一个例子:待发送的信息为101001,生成多项式为G(x) = x^3 + x^2 + 1 ,计算余数

  1. 生成多项式
G(x) = x^3 + x^2 + 1 
	 = 1 * x^3 + 1 * x^2 + 0 * x + 1 * x^0
  1. 生成多项式各项系数构成的比特串1101
  2. 计算冗余码
    1. 构造被除数,在待发送信息的后面添加生成多项式最高次数个0,即 101001 + 000(最高次为 3)
    2. 构造除数,即生成多项式各项系数构成的比特串 1101
    3. 做除法:
    4. 最后余数的位数应该要和生成多项式的最高次数相同,如果位数不够就在前面补0来凑足位数
  3. 得出结果为 001

检错码只能检测出帧在传输过程中出现了差错,但是无法定位错误

纠错码可以进行前向纠错,但是开销比较大,冗余信息更多,在计算机网络中使用很少

计算机网络中更多使用我们马上要讨论的检错重传方式或者丢弃检测到差错的帧


三、可靠传输

刚才我们讲到,可以使用CRC循环冗余检错码判断帧在传输过程中出现了差错,接下来如何去做取决于数据链路层向上提供的服务类型是可靠传输还是不可靠传输

不可靠传输:仅仅丢弃有误码的帧,什么都不做

可靠传输服务:想办法实现,发送端发送了什么,接收端就要收到什么

那么什么时候使用可靠传输,什么时候使用不可靠传输呢?一般来讲:

  • 由于有线传输的误码率较低,一般为了节省开销而使用不可靠传输
  • 无限传输的误码率较高,要求数据链路层必须向上层提高可靠传输

当然,传输的差错也不仅仅有上述的比特差错,还有:

  • 分组丢失:例如交换机缓存已满,会把传入的分组丢失
  • 分组失序:会把数据分组进行发送,但是由于网络原因,可能传过去的分组的顺序不是顺序发送
  • 分组重复:可能由于网络原因,在某个交换机停留了很久,触发了发送端的超时重传,而导致分组重复 为了实现可靠传输,我们有以下三种策略:

1. 停止-等待协议 SW

所谓“停止-等待”,就是在发送数据分组后,停止发送其他的数据分组,而是等待接收方返回的ACK、NAK

  • 发送方发送一个数据分组
  • 接收方进行差错校验(CRC):
    • 如果有误码则丢弃,并返回NAK,发送方从缓存中重发该消息
    • 如果无误码则接受,并返回ACK,发送方发送下一个消息,并从缓存中删除该数据分组

问题一但是如果接受方没有接受到数据分组,那么无法返回ACK或者NAK,发送方会一直阻塞吗?

为了解决这个问题,发送方可以在每发送一个数据分组就启动一个超时计时器,若到了超时计时器锁设置的超时重传时间,发送方就会重传缓存中的数据分组

一般会把超时重传的时间设置为 略大于收发双方的平均往返时间 RTT

问题二如果接收方返回的ACK丢失了,那么就会触发发送方的超时重传,是不是会出现数据的重复消费?

为了解决这个问题,给每个数据分组加上了序号,由于发送方的发送是阻塞的,每次只能发送一个分组,所以就可以使用0和1来编号就够了,这样只需要判断这次消费的数据和上次的消费数据的编号是否一致即可

问题三如图,如果接收方返回的ACK时间比较长,同时也触发了超时重传,也就是发送了重复的数据分组,此时ACK的消息接收了,就会发送下一个数据分组,但是重传的数据分组的ACK就会导致下一个数据分组接收:

为了解决这个问题,我们可以给 ACK 也进行编号,这样就可以做到ACK的时候重复ACK的问题,这样在ACK的时候判断即可


其实说到这里,不难发现,停止-等待协议是一种阻塞的形式进行发送消息,信道的利用率是很低的:

其中真正有效的时间就是Td,也就是发送数据分组的时间,如果出现超时重传,信道的利用率要更低


2. 回退N帧协议 BGN

在停止-等待协议中,随着 RTT 的变大,信道的利用率也会变低(卫星通信),一般这种情况可以选择使用回退N帧协议或者选择重传协议

对于停止等待协议,我们不难发现是因为它是一种阻塞的传输方式,而回退N帧协议,采用了流水线进行传输:

同样为了防止重复消费,我们需要给数据分组进行编号,现在假设使用3位来进行编号,那么就是 0 ~ 7 号:

发送方不能无限制地连续发送数据分组,需要维护一个发送窗口,在未收到接收方确认分组的情况下,发送方可以把窗口内的所有数据分组发出去

  • 发送窗口的取值范围是 1 < W<sub>T</sub> < 2^n - 1
  • 本例的取值范围就是 2 ~ 7,取 W<sub>T</sub> = 5

接收方需要维护一个接收窗口 WR,只有正确到达接收方无误码,并且序号落入窗口内的数据分组才能被接收方接收

  • 接收窗口的取值只能是 1
  • 接受方每正确收到一个数据分组,就会发送一个ACK确认分组,接受窗口就会向前滑动一个位置,这样就会有一个新的序号落入接收窗口

在没有传输差错的情况下,具体的过程是这样的:

  • 发送窗口发出编号为0、1、2、3、4的五个数据
  • 接收窗口首先收到DATA 0然后返回ACK 0,向前滑动一步到编号为 1 的数据
  • 发送窗口收到ACK0往后滑动一步,此时覆盖的就是1~5,发送数据分组DATA 5
  • 接收窗口首先收到DATA 1然后返回 ACK 1,向前滑动一步到编号为 2 的数据
  • 发送窗口收到ACK1 往后滑动一步,此时覆盖的就是2~6,发送数据分组DATA 6
  • ……………………

问题一如果产生了误码,回退N帧协议是如何处理的呢?

例如:发送窗口发送了 0 ~ 4 的四个数据单元,其中 DATA 2 发生了误码,那么根据上述的描述,接受方窗口理应在编号为 2 的位置,由于发现了误码,因此不会回传 ACK 2,而是会丢弃2、3、4这三个数据单元,不管3、4两个数据单元是否有误码都会丢弃,同时返回最后一个成功接收的编号,即 ACK 1,方便发送方尽快重传,而不是等待超时重传

问题二是不是每次接受都会返回 ACK 呢?

其实回退N帧协议的接收方采用累积确认的方式:

  • 接收方不用对收到的每个数据分组都确认,而是可以在收到连续的几个序号后,返回最后一个数据分组发送确认消息
  • 即如果成功接收了编号为0、1、2、3、4,只需要返回 ACK 4 表示前面的都已经被正确接受
  • 优点
    • 如果其中 ACK 1 在返回的时候丢失了,ACK 2 也可以表示编号为 1 的数据分组成功接收,而不是超时重发,也就是 ACK丢失不一定需要重发数据分组
    • 同时,减少了网络中注入确认分组的数量
  • 缺点:不能向发送方及时反映出接收方已经正确接受的所有分组的数量,也就是说即时性不强

问题三在说到发送窗口的大小的时候,我们提到,只能取值为1 < WT < 2^n - 1,为什么不能大于那个取值呢?

我们同样以三个比特给分组编号为例,也就是编号为 0 ~ 7,而发送窗口的大小只能选择为 2 ~ 7。

  • 如果发送端口为 8
  • 也就是说我们第一次会发送出 0、1、2、3、4、5、6、7 八个数据分组
  • 如果由于网络延迟原因,触发了超时重传
  • 那么就会出现再次发过去的时候,根据编号无法判断是滑动窗口下滑后的八个数据分组,还是本来的八个数据分组

因此,WT不能超过取值范围,会导致无法判断新旧数据分组的问题


3. 选择重传协议 SR

回退N帧协议的接受窗口尺寸只 能为1,因此接收方只能按序正确接受正确到达的数据分组

这样就会导致:尽管后续的数据没有误码,但是由于一个数据分组的误码,而丢弃所有的数据分组,造成了通信资源的极大浪费

为了进一步提高性能,可以让接受窗口尺寸大于1,接收方先收下失序到达但是没有误码、序号落在接受窗口内的数据分组,等到所缺的分组收齐后再一起送到上层,这就是选择重传协议

问题一是否还能采用累积确认呢?

为了让发送方进重传出现差错的数据分组,接收方是不再采用累积确认,而是需要对每个正确接受的数据分组逐一确认,进而可以判断是哪个数据分组传输出现差错

问题二发送窗口的大小和接受窗口的大小的范围是多少?如果超过范围会怎么样呢?

  • 发送窗口的大小为:1 < W<sub>T</sub> ≤ 2^(n-1)
  • 接受窗口的大小为:1 < W<sub>R</sub> ≤ W<sub>T</sub>

如果接受窗口的大小大于发送窗口的大小,这是无意义的,因为最多发送的数据分组有限,类似于“带宽再大,没有这么多流量,也是无意义的

如果发送窗口的大小大于 2^(n-1),仍然以三位进行编号来举例,也就是取发送窗口的大小为 5、接受窗口的大小仍然为 4:

  • 如果发送方发送了 0 ~ 5,接收方成功接收,滑动窗口移动到5 ~ 0,并返回 ACK
  • 但是其中 ACK0 丢失,而ACK1、2、3、4正常,因此会重发 0这个数组分组
  • 此时就会发现:无法辨别新旧数据分组

💬 总结

本文我们首先了解到了,数据链路层是基于物理层这个链路,加上了实现协议的硬件和软件,为上层提供透明传输的一层,而想要提供透明传输,就需要解决三个问题:

  1. 封装成帧:由于实现的协议不同,不同种帧的结构自然也是不同,不过它们都要解决如何定位一个帧这个问题
    1. 对于 PPP 帧,采用了 帧定界符 + 转义字符 解决了这个问题
    2. 对于 MAC 帧,帧头的标识是利用物理层加上的前导码,而帧尾的标识是利用相邻帧之间的 96 比特时间
  2. 差错检测:这里我们说的仅仅是误码这一种差错,而真正的差错还包含分组丢失、分组失序、分组重复,而如何检测出误码,就要使用到CRC 循环冗余校验,通过提供的例子能更快的理解它的计算方式
  3. 可靠传输:对于有线链路,我们一般使用不可靠传输,因为它的误码率比较低,而无限链路,我们要提供可靠传输,而实现可靠传输的策略有以下三种:
    1. 停止-等待协议 是一种阻塞的方式,一次性只能发送一个消息,信道的利用率较低,特别是对于 RTT 往返时间 比较大的时候(卫星通信),信道的利用率很低
    2. 回退N帧协议 相较于前者,使用到了滑动窗口模式,以流水线的方式提高了信道的利用率,但是对于质量不好的信道,一直发生误码,由于它发现误码会丢弃所有的分组,信道利用率也会降低
    3. 选择重传协议 为了解决遇到误码就丢弃所有分组这个问题,为接受方也开启了滑动窗口,接收方先收下失序到达但是没有误码、序号落在接受窗口内的数据分组

🍁 友链


✒写在最后

都看到这里啦~,给个点赞再走呗~,也欢迎各位大佬指正以及补充,在评论区一起交流,共同进步!也欢迎加微信一起交流:Goldfish7710