小白笔记
本节学习可靠数据传输的原理,这是重中之重!
在本节中,我们在一般场景下考虑可靠数据传输的问题,因为可靠数据传输的实现问题不仅在运输层出现,也会在链路层及应用层出现。
1.可靠数据传输(rdt)的原理
·rdt在应用层、传输层和数据链路层都很重要
·是网络TOP10问题之一,就是非常经典的一些问题
·信道的不可靠特点决定了可靠数据传输协议(rdt)的复杂性
2.可靠数据传输:问题描述
要记住rdt_send()和deliver_data()是本层跟上层的接口,然后udt_send()和rdt_rcv()是本层实意实体跟下层的原语接口形式。
通过调用rdt_send()函数,上层可以调用数据传输协议的发送方。它将要发送端数据交付给位于接收方的较高层。在接收端,当分组从信道的接收端到达时,将调用rdt_rcv()。当rdt协议需要向叫高层交付数据报时,将通过调用deliver_data()来完成。 我们很快可以看到,除了交换含有待传送的数据的分组之外,rdt的发送端和接收端还需完饭控制分组,rdt的发送端和接收端都要通过调用udt_send()发生分组给对方(其中udt标识不可靠数据传输)
我们将:
·渐增式的开发可靠数据传输协议(rdt)的发送方和接收方
·只考虑单向数据传输,但控制信息总是双向流动的!(双向的数据通信相当于两个单向的数据通信,我们学原理,把一个方向学清楚了,另外一个方向也是一样的)双向的数据传输问题实际上是2个单向数据传输问题的综合。
·使用有限状态机(FSM)来描述发送方和接收方
状态1--->引起状态变迁的事件/转态变迁时采取的动作--->状态2
状态:在该状态时,下一个状态只由下一个事件唯一确定
这里如果对一个事件没有动作或没有就事件发生而采取了一个动作,我们将在横线上/下方使用A表示,FSM的初始状态用虚线来表示。
3.Rdt1.0:在可靠信道上的可靠数据传输
·下层的信道是完全可靠的(·没有比特出错·没有比特分组丢失)
·发送方和接收方的FSM
·发送方将数据发送到下层信道
·接收方从下层通信接收数据
发送方:等待来自上层的调用。这是发送方初始化的一个虚线:上面来了data(rdt_send(data))要我传的数据,然后我要封装本层的packet(packet=make_pkt(data)),即把上层来的协议数据单元封装成本层的协议数据单元,然后通过下层接口把packet打走(udt_send(packet)),然后又回到这个状态。发送方就做接收封装打走这样的动作。
接收方:等待来自下层的调用。接收方等待下面来packet然后接收分组(rdt_rcv(packet()),然后把packet当中的data解封装(extract(packet data)),然后把解封装后的data交给上层(deliver_data(data))。接收方就是做解封装、交互这样的动作。
4.Rdt2.0:具有比特差错的信道
·下层信道可能会出错:将分组中的比特翻转,用校验和来检测比特差错
·问题:怎样从差错中恢复:
·确认(ACK) :接收方显式地告诉发送方分组已被正确接收
·否定确认(NAK): 接收方显式的告诉发送方分组发生了差错,发送方收到NAK后,发送方重传分组
·rdt2.0中的新机制:采用差错控制编码进行差错检测
·发送方差错检测控制编码、缓存
·接收方使用编码检错
·接收方的反馈:控制报文(ACK、NAK):接收方->发送方
·发送方收到反馈相应的动作
rdt2.0:没有差错时的操作就如上图,接收方在等待上层的调用,发送方来了data新增packet,再通过下层接口放走packet,然后同时进入到等待确认状态,然后接收方收到一个分组,分组没有出错,解封装,然后交付同时要给发送方说谢谢即ACK,谢谢到了发送方,然后发送方就重新回到这个状态,这个状态就是上面再发送新的data,发送方才可以发新的packet给接收方。如果接收方收到的分组是出错的情况,分组没有通过校验,接收方就给一个NAK给对方,发送方接收到NAK,就把刚刚传给接收方的packet重传给接收方,假如重发的是对的通过了校验,接收方再给发送方ACK。
rdt2.0的发送端有两个状态。在最左边的状态中,发送端协议正等待来自上层传下来的数据。当rdt_send(data)事件出现时,发送方将产生一个包含发送数据的分组(sndpkt),带有校验和,然后经由udt_send(sndpkt)操作发生该分组。在最右边的状态中,发送方协议等待来自接收方的ACK/NAK分组。如果收到一个ack分组,则发送方知道最近发送的分组已经被正确接收,一次协议返回到等待来自上层的数据的状态。如果收到一个NAK分组,该协议重传上一个分组并等待接收方为响应重传分组而回送的ACK/NAK。注意到下列事实很重要:就是,rdt_send()事件不可能出现,仅当接收端ACK并离开该状态时才能发生这样的事件。一次,发送方将不会发生一块新的数据,除非发送方切削接收方已经正确接收当前分组。由于这种行为,rdt2.0这样的协议称为停等协议。
rdt2.0接收方的FSM仍然只有单一状态。当分组到达时,接收方要么回答一个ACK,要么回答一个NAK,取决与收到的分组是否受损。符号rdt_rev(revpkt)&&corrupt(rcvpkt)对应于收到一个分组并发现有错的事件。
5.rdt2.0的致命缺陷!->rdt2.1
如果ACK/NAK出错?(发送方发给接收方的packet可能出错,那接收方发送给发送方的ACK/NAK也可能出错呀)
·发送方不知道接收方发生了什么事!那发送方应该咋做?重传?可能重复,不重传?可能死锁或出错
·需要引入新的机制-->序号
也就是在分组中加入序号,加序号的目的是什么呢?如果接收方发过来的ACK/NAK出错,不管三七二十一,发送方都重传一遍,因为带序号呀,假设第一次发的是P0,假设接收方发错的那个原本是ACK,那我再重发一次P0,接收方它看到又重发了一个P0,那它就知道自己传出去的ACK出错了呀(因为我刚才就接收到P0了然后回了一个ACK,而你现在又发一个P0给我,那接收方就知道是自己刚才发送出去的ACK出问题了),然后丢掉重发的P0,并且仍然给发送方发个ACK,再给发送方发送个ACK就是为了告诉发送方可以发下一个啦不用再重发啦,比如可以发P1啦。
处理重复:
·发送方在每个分组中加入序号
·如果ACK/NAK出错,发送方重传当前分组
·接收方丢弃(不发给上层)重复分组
就是停等协议:发送方发送一个分组,然后等待接收方的应答(发一个等待对方确认再发新的,不会发一个还没确认就继续发下一个)
rdt2.1:讨论
发送方:
·在分组中加入序列号
·两个序列号(0,1)就足够了(一次只发送一个未经确认的分组,所以只用一位代表序列号就行,后面还有流水线协议所以用多位)
·必须检测ACK/NAK释放出错(需要EDC)
·状态数变成了两倍(必须记住当前分组的序列号为0还是1)(以前只要等待发送就行了嘛现在要等待0等待1,所以状态数变成了两倍)
接收方:
·必须检测接收到的分组是否是重复的(状态会指示希望接收到的分组的序号为0还是1)
·注意:接收方并不知道发送方是否正确收到了其ACK/NAK(没有安排确认的确认,具体解释见下面)
6.rdt2.2:无NAK的协议
·功能同rdt2.1,但只使用ACK(ACK要编号)
·接收方对最后正确接收的分组发ACK,以替代NAK,接收方必须是显式地包含被正确接收分组的序号
·当收到重复的ACK(如:再次收到ack0)时,发送方与收到NAK采取相同的动作:重传当前分组
·为后面的一次发送多个数据单位做一个准备
·一次能够发送多个(到后面流水线协议一次发送多个,每一个你都ACK/NAK是不是很麻烦呀)
·每一个的应答都有:ACK,NACK:麻烦
·使用对前一个数据单位的ACK,代替本数据单位的NAK
·确认信息减少一半,协议处理简单
到后面流水线协议一次发送多个每次都正向确认ACK/反向确认NAK很麻烦,那么我们可以用,就是我在等1的时候,你传的1错了,我不谢谢你1而是谢谢你前面的0,就代表刚才传的1出错了,然后再重传1。对当前分组的一个反向确认用前面分组的一个正向确认来代替,但是我们对ACK做编号,那这样的话我们就可以不用NAK了,那这样的话我们可以从停止等待协议升级到流水线协议做一些准备。如果是ACK0出错也是同理,发送方再重发P0,接收方发现又重发了P0就知道P0出现错误了,然后扔掉重发的P0,接收方再发ACK0(这次ACK0没错了),然后发送方就可以发送P1了。和2.1差别不大,只是用上一个分组的ACK代表NAK。
7.rdt3.0:具有比特差和分组丢失的信道
新的假设:之前是分组受损的可能,现在下层信道也可能会丢失分组(数据或ACK)那该怎么办
·会死锁
·机制还不够处理这种状况:·校验和 ·序列和 ·ACK ·重传
方法:发送方等待ACK一段合理的时间
·发送端超时重传:如果到时候没有收到ACK->重传
·问题:如果分组(或ACK)只是被延迟了:·重传将会导致数据重复,但是利用序列号已经可以处理这个问题 ·接收方必须指明被正确接收的序列号
·需要一个倒计数定时器
发送方发送P0,接收方发送ACK0,然后接收方发送P1,然而传给接收方途中丢失,这时候发送方在等待接收方的应答,接收方在等待P1,就会导致死锁,所以就需要一个机制来处理分组丢失,这个机制叫超时重传机制,重传时间一般比正常往返稍微多一点时间,时间一过接收端后面收到就重传。
为了实现基于时间的重传机制,需要一个倒计数定时器,在一个给定的时间量过期后,可中断发送方。一次,发送方需要能做到:·每次发送一个分组时(包括第一次分组和重传分组),便启动一个定时器。 ·响应定时器中断(采取适当的动作)·终止定时器
3.0与2.2不一样的,第一,发送方发送一个分组后要启动超时计时器,然后接收方在发送方等待确认的时候会有一个事件,超时事件启动后要把刚才的分组重发一遍同时仍然启动超时计时器。第二发完0再发1,然后我在等1,来了0号分组的确认,发送方不动,等着超时器重传1。
rdt3.0是个比较完美的协议,能够对抗分组丢失和分组出错,但是有个致命的问题,就是在信道容量比较大的时候,它的信道利用率比较低,因此我们需要一次发送多个未经对方确认的分组,即流水线协议。
rdt3.0性能
·rdt3.0可以工作,但链路容量比较大的情况下,性能很差
·链路容量比较大,一次发一个UDP的不能够充分利用链路的传输能力
8.流水线协议:
流水线:允许发送方在未得到对方确认的情况下一次发送多个分组
·必须增加序号的范围:用多个bit表示分组的序号
·在发送方/接收方要有缓冲区
·发送方缓冲:为得到确认,可能要重传
·接收方缓存:上层用户取用数据的连接不等于接收到的数据速率:接收到的数据可能是乱序,排序交付(可靠)
·两种通用的流水线协议:回退N步(GBN)和选择重传(SR)
为了区别GBN和SR,我们先来简单了解一下滑动窗口协议
(1)通用:滑动窗口(side window)协议
·发送缓冲区(主要目的是发送方发送完毕后把分组放在缓冲区中,以备检错重发超时重发)
·形式:内存中的一个区域,落入缓冲区的分组可以发送
·功能:用于存放已发送,但是没有得到确认的分组
·必要性:需要重发时可用
·发送缓冲区的大小:一次最多可用发送多少个未经确认的分组
·停止等待协议=1
·流水线协议>1,合理的值,不能很大,链路利用率不能够超过100%
·发送缓冲区中的分组
·未发送的:落入发送缓冲区的分组,可以连续发送出去
·已经发送出去的,等待对方确认的分组:发送缓冲区的分组只有得到确认才能删除
SW为发送窗口,RW为接收窗口,S-W为停止等待协议:
如果SW=1,RW=1,则S-W
如果SW>1,RW=1,则GBN
如果SW>1,RW>1,则SR
(后面两个称为流水线协议)
1)滑动窗口协议--发送窗口:
·发送窗口:发送缓冲区内容的一个范围,那些已经发送但是未经确认分组的序号构成的空间
·发送窗口的最大值<=发送缓冲区的值
·一开始:没有发送任何一个分组
·后沿等于前沿 ·之间为发送窗口的尺寸=0
·每发送一个分组,前沿前移一个单位
发送窗口的移动->前沿移动
·发送窗口前沿移动的极限:不能够超过发送缓冲区
发送窗口的移动->后沿移动
·发送 窗口后沿移动
·条件:收到老分组的确认
·结构:发送缓冲区罩住新分组,来了分组可以发送
·移动的极限:不能够超过前沿
讲完发送窗口接下来看看接收窗口
2)滑动窗口协议--接收窗口
·接收窗口=接收缓冲区
·接收窗口用于控制哪些分组可以接收 ·若序号在接收窗口之外,则丢弃
·接收窗口尺寸Wr=1,则只能顺序接收;
·接收窗口尺寸Wr>1,则可以乱序接收,但是交给上层的分组,要按序
比如Wr=1,0分组来了则接收方发送ACK0,然后继续移动窗口,然后1来了,接收方发送 ACK1就是按顺序接收,ACK是按顺序发送0到1再到1再到2这样下去,这里ACK2意味着收到2了也收到2前面的那些了。而如果Wr>1,比如接收窗口长度为五,然后此时罩在2,3,4,5,6,然后接收方接收到了4再接收到了3,则会按接收顺序先发送ACK4再发送ACK3,发送ACK3仅仅意味着我接收到了分组3,并不意味着我接收到了3以及3前面的分组,因为没有接收到2,所以接收窗口不能往前移动,只有等2接收到了,接收窗口才能往前移,这时候它要做几个动作,把2,3,4号分组的数据分组解封装,然后一起交给上层的用户,同时接收窗口滑动到5这个位置上。
·例子:Wr=1,在0的位置;只有0号分组可以接收;
向前滑动一个,罩在1的位置,如果来了第2号分组,则丢弃
·接收窗口的滑动和发送确认
·滑动:
·低序号的分组的到来,接收窗口移动
·高序号分组乱序列,缓存但不交付(因为要实现rdt,不允许失序),不滑动
·发送确认:
·接收窗口尺寸=1:发送连续收到的最大的分组确认(累计确认,就是接收到ACK2,就代表2及2之前的都收到了)
·接收窗口尺寸>1:收到分组,发送那个分组的确认(非累计确认,就是接收到ACK2,只说明接收到了分组2)
正常情况下的2个窗口互动:
·发送窗口:
·有新的分组落入发送缓冲区范围,发送->前沿滑动
·来了老的低序号分组的确认->后沿向前滑动->新的分组可以落入发送缓冲区的范围
·接收窗口:
·收到分组,落入到接收串口范围,接收
·是低序号,发送确认给对方
·发送端上面来了分组->发送窗口滑动->接收窗口滑动->发确认
整个过程差不多是这样:在发送方它的用户有分组发送,推动了发送窗口向前滑动,发送窗口向前滑动,意味着接收窗口向前滑动,接收窗口向前滑动然后发送确认,接收窗口的确认带动了发送窗口向前滑动,发送窗口滑动结果呢发送缓冲区可能有新的分组落入缓冲区内。
异常情况下GBN的2窗口互动:
·发送窗口:
·新分组落入发送缓冲区范围,发送->前沿滑动
·超时重发机制让发送端将发送窗口中的所有分组发送出去
·来了老分组的重复确认->后沿不向前滑动->新的分组无法落入发送缓冲区的范围(此时如果发送缓冲区有新的分组可以发送)
·接收窗口:
·收到乱序分组,没有落入到接收窗口范围内,抛弃
·(重复)发送老分组的确认,累计确认
因为是GBN它得按序呀,比如该接收2的情况下接收到了2后的3分组,因此3会被抛弃掉,然后是发送1号分组的确认,并且接收窗口不动仍然在2号分组那,那对于发送方而言接收方发送的是老分组的确认ACK1,因此发送方发送窗口没有办法向前滑动的,最后会照成超时重发机制(只设置一个超时定时器),导致发送方把发送窗口中的所有分组都重新发一遍。
异常情况下SR的2窗口互动:
·发送窗口:
·新分组落入发送缓冲区范围,发送->前沿滑动
·超时重发机制让发送端将超时的分组重新发送出去
·来了乱序分组的确认->后沿不向前滑动->新的分组无法落入发送缓冲区的范围(此时如果发送缓冲区有新的分组可以发送)
·接收窗口:
·收到乱序分组,落入到接收窗口范围内,接收
·发送该分组的确认,单独确认
因为是SR,按前面讲过的例子,发送方接收到ACK4,ACK3,发送方就知道3,4没有必要再重发,那么带来的结果是2号分组的确认始终到达不了发送方,那么2号分组的定时器会超时,那么这时候超时重传机制会让发送方重发2号分组,而2之后的3,4等不会进行重新发送。补充一句,发送方在SR即选择重发当中,发送方也是一次可以发送多个未经确认的分组,而且每发送一个分组,发送方都会启动一个超时计时器,哪个超时计时器到时,发送方就单独的重新发送那个分组,接收方每收到一个分组就把该计时器关掉。
GBN(回退N步)协议和SR(选择重传)协议的异同
·相同之处:·发送窗口>1 ·一次能够可发送多个未经确认的分组
·不同之处:
·GBN:接收窗口尺寸=1
·接收端:只能顺序接收
·发送端:从表现来看,一旦一个分组没有发成功,如:0,1,2,3,4;假如1未成功,234都发送出去了,要返回ACK1再发送所以分组:GB1
·SR:接收窗口尺寸>1
·接收端:可以乱序接收
·发送端:发送0,1,2,3,4,一旦1未成功,234已发送,无需重发,选择性发送1
流水线协议:总结
Go-back-N(GBN):
·发送方最多在流水线中有N个未确认的分组
·接收端只是发送累计型确认(累计确认),接收端如果发现gap,不确认新到来的分组
·发送端拥有对最老的未确认分组的定时器
·只需设置一个定时器
·当定时器到时时,重传所有的未确认分组
Selective Repeat:
·发送端最多在流水线中有N个未确认的分组
·接收方对每个到来的分组单独确认(非累计确认)
·发送方为每个未确认的分组保持一个定时器
·当超时定时器到时,只是重发到时的未确认分组
GBN与SR行为表现差异主要原因是窗口大小原因,一个等于1一个大于1。
对比GBN和SR:
优点:
GBN:简单,所需资源很少(接收方一个缓存单元) SR:出错时,重传一个代价小
缺点:
GBN:一旦出错,回退N步 SR:复杂,所需资源多(接收方多个缓存单元)
·适用范围:
·出错率低:比较适合GBN,出错非常罕见,没有必要用复杂的SR,为罕见的事件做日常的准备和复杂处理
·链路容量大(延迟大、宽带大):比较适合SR而不是GBN,一点出错代价太大