可靠数据传输(rdt)的原理

可靠数据传输(rdt)的原理

  • rdt在应用层、传输层和数据链路层都很重要【不出错、不重复、不丢失】
  • 是网络TOP 10问题之一

【sending process:发送方进程;receiver process:接收方进程。要实现可靠数据传输,发送方进程传输data过来就要原原本本传给接收方进程。要实现可靠数据传输需要借助下层提供所服务去实现;下层提供的服务是UDT,不可靠的传递,发送方上面交下来的东西叫data,本层协议通过下层交付的东西把data前面封装一些头部,形成本层的packet,借助下层提供的一些服务,在发送方调用udt_send()这样的原语,对方udt_rcv()[图片写错了] 可能会收到、也可能收不到packet,收到的packet可能乱序。不管怎么样要向上层交付原原本本的data】

【rdt面临的服务很复杂,需要向上层提供可靠的数据传输,但是依赖的下层服务却不怎么可靠,可能会出错、丢失、乱序】

  • 信道的不可靠特点决定了可靠数据传输协议(rdt)的复杂性

可靠数据传输:问题描述

【发送方调用rdt_send(),把data通过层间接口,把data封装成packet,借助于发送方可靠传输实体跟下层接口udt_send()往下去发,channel是不可靠的channel,接收方通过udt_rcv()收到packet,也可能收不到,最后把packet中的data取出来,排序后,有序地、可靠地、正确地,通过deliver_data()这样的原语交给接收方的进程】

【rdt_send()和deliver_data()是本层和上层的接口,udt_send()和udt_rcv()是本层协议实体跟下层的原语的形式】

我们将:

  • 渐增式地开发可靠数据传输协议(rdt)的发送方和接收方【渐增式:逐一解决channel的不可靠问题。底层channel的不可靠性决定了协议的复杂性】
  • 只考虑单向数据传输【双向的数据通信相当于两个单向的数据通信】
    • 但控制信息是双向流动的【数据假设是单向的,但是控制信息需要有反馈,所以控制信息是双向的】
  • 双向的数据传输问题实际上是2个单项数据传输问题的综合
  • 使用有限状态机(FSM)来描述发送方和接收方【FSM实际上就是描述协议如何工作的工作机制的一个形式化描述方案,要比语言描述更简洁更易理解更便于检查】

状态:在该状态时,下一个状态只由下一个事件唯一确定

【节点代表状态,边上的标记label——分子代表事件、分母代表状态变迁过程中的一些动作】

【后面就用FSM代表协议动作的机制、原理】

Rdt 1.0:在可靠信道上的可靠数据传输

  • 下层的信道是完全可靠的【假设channel不出错、不丢失】
    • 没有比特出错
    • 没有分组丢失
  • 发送方和接收方的FSM
    • 发送方将数据发送到下层信道
    • 接收方从下层信道接收数据

【发送方:虚线是初始化的一个虚线,只做接收、封装、打走。上层来的服务数据单元,把他封装成本层的协议数据单元,然后通过下层的接口把他打出去。】

【本层协议的实现要借助于下层所提供的服务,实现本层协议的目的是为了向上层提供更好的服务。所以一定有上层原语的调用、下层服务的调用、本层的协议动作。假如把上层和下层接口都定下来之后,我们来看本层协议实体要做哪些动作、要安排哪些时空的资源,从而向上层提供更好的服务,这就是我们的目标。】

【接收方:等待packet、解封装、通过层间接口交给上层用户。所以接收方做解封装、交付的动作】

【rdt1.0只是做封装和解封装】

Rdt 2.0:具有比特差错的信道

  • 下层信道可能会出错:将分组中的比特翻转【把其中一个假设去掉,本层协议数据单元packet在传的过程可能出现翻转(1变成0、0变成1)】
    • 用校验和来检测比特差错
  • 问题:怎样从差错中恢复:
    • 确认(ACK):接收方显示地告诉发送方分组已被正确接收

【P是packet】

    • 否认确认(NAK):接收方显示地告诉发送方分组发生了差错
      • 发送方收到NAK后,发送方重传分组

【发送方收到NAK后,发送方重传分组】

  • rdt2.0中的新机制:采用差错控制编码进行差错检测
    • 发送方差错控制编码、缓存【发送方要做差错控制编码,发送方发完之后要留一个副本,以备检错重传】
    • 接收方使用编码检错【接收方要做差错控制解码】
    • 接收方的反馈:控制报文(ACK,NAK):接收方->发送方【接收方要给个反馈】
    • 发送方收到反馈相应的动作【发送方根据反馈做相应动作:发老的还是发新的,发老的就是收到了NAK检错重传】

rdt2.0:FSM描述

【发送方两个状态:一个是等待上层的调用,一个是等待NAK或者ACK;接收方只有一个状态:等待下层的调用。】

【发送方初始化等待上层的调用,等待上层发数据,rdt_send(data),data来之后要把它封装成packet,在封装的时候要计算checksum检验和,data、checksum一起封装成packet,通过下层接口把它放出去(udt_send(sndpkt));放完之后进入等待接收方反馈的状态,如果对方给的是ACK就什么都不做,等待上层调用新的data,然后发新的data;如果对方给的是NAK,把刚刚封装的packet重放一遍,这里就是检错重传,传完之后还要等对方的ACK或者NAK,直到收到ACK才传新的】

【接收方等待下层的调用,如果接收方来了一个分组,没有出错,(没有corrupt,没有腐败,D和EDC通过了差错控制编码关系,通过了校验),然后就解封装,通过层间接口往上交,然后还要向发送方发送ACK。如果收到一个分组错了,没通过校验,给对方发一个NAK】

rdt2.0:没有差错时的操作

rdt2.0:有差错时

rdt2.0的致命缺陷!-> rdt2.1

如果ACK/NAK出错?

  • 发送方不知道接收方发生了什么事情!
  • 发送方如何做?
    • 重传?可能重复
    • 不重传?可能死锁(或出错)
  • 需要引入新的机制
    • 序号

处理重复:

  • 发送方在每个分组中加入序号
  • 如果ACK/NAK出错,发送方重传当前分组
  • 接收方丢弃(不发给上层)重复分组【有可能出现重复的分组,但是接收方是能够检测出重复的分组的,因为增加了序号,重复了就扔了,扔了仍然发一个ACK,从而发送方再发一个新的】

【在ACK/NAK本身出错的情况下,把刚刚放送的packet重新放送一遍,有可能出现重复,但是由于在packet当中有序号,是能检查出重复,重复就丢掉,然后仍然发ACK,让发送方发新的packet,然后双方又重新回到一个同步的状态】

停等协议——发送方发送一个分组,然后等待接收发的应答【发完之后stop,wait对方的确认】

rdt2.1:发送方处理出错的ACK/NAK

【初始化等待上层调用0,也就是说来了data封装packet序号是0,然后还有checksum,通过下层接口把它放出去,然后等待ACK或NAK 0,如果接收到的是ACK,那么就进入等待来自上层的调用1在;如果ACK或者NAK分组本身出错或者收到NAK,就要把packet0重传一遍,有可能出现重复,接收方是可以通过序号把他校验出来。1的状态和0的状态是对称的,发送方有4个状态】

rdt2.1:接收方处理出错的ACK/NAK

【接收方就两个状态:等待来自下层的调用0、等待来自下层的调用1。发送方从0案开始接收方就从0开始,发送方从1开始接收方就从1开始。接收方在等待序号0分组,这时来了分组、没出错、是序号0分组,把packet当中data取出来,data取出来通过层间接口交给上层,形成ACK,ACK本身也要chksum,通过层间接口把他放出去;然后到了等待1的状态,然后收到一个分组、没出错、是一个序号1的分组,然后解封装、向上交付、形成ACK往下交,然后又回到等待0分组的状态。假如发了0之后等待1,这时来了一个分组,分组没出错,但是来的是0分组,给对方一个ACK的packet,然后通过层间接口把它放出去(ACK重放)。如果等待1,这时来了一个分组,分组出错了,给对方NAK】

【共有三种事件:一种是分组是对的也是等待的分组,解封装、向上交付、形成ACK往下交;一种是分组是对的但不是等待的分组,形成ACK往下交;还有一种是分组是错的,形成NAK往下交】

rdt2.1:讨论

发送方:

  • 在分组中加入序列号
  • 两个序列号(0,1)就足够了【区分出老的和新的就行】
    • 一次只发送一个未经确认的分组【停等协议】
  • 必须检测ACK/NAK是否出错(需要EDC)【ACK确认也需要校验】
  • 状态数变成了两倍
    • 必须记住当前分组的序列号为0还是1

接收方:

  • 必须检测接收到的分组是否是重复的
    • 状态会指示希望接收到的分组的序号为0还是1
  • 注意:接收方并不知道发送方是否正确收到了其ACK/NAK
    • 没有安排确认的确认【接收方不知道发送方有没有收到确认,是根据后面的表现(接收到的是不是希望接受的分组)才知道发送方有没有收到确认或者反向确认。确认的确认不具备完备性,所以不安排确认的确认也是更高级的确认】

rdt2.1的运行

【重复的分组不向上交付,给对方一个ack,给ack的目的是让发送方发packet0之后的packet1】

接收方不知道它最后发送的ACL/NAK是否被正确地收到

  • 发送方不对收到的ack/nak给确认,没有所谓的确认的确认
  • 接收方发送ack,如果后面接收方收到的是:
    • 老分组p0?则ack错误
    • 下一个分组?p1,ack正确

rdt2.2:无NAK的协议

  • 功能同rdt2.1,但只使用ACK(ack要编号)【不用NAK,只用ACK,把ACK编号】
  • 接收方对最后正确接收到的分组发ACK,以替代NAK
    • 接收方必须显式地包含被正确接受分组的序号【比如传的是packet1,接收方如果收到了正确的就发ack1,如果收到的分组有问题就发ack0(上一个ack),那么发送方就重传】
  • 当收到重复的ACK(如:再次收到ack0)时,发送方与收到NAK采取相同的动作:重传当前分组【当前分组的反向确认用前面分组的正向确认来代替包括的语义形式是一样的,但是要对ack进行编号,这样就可以不要NAK】
  • 为后面的一次发送多个数据单位做一个准备
    • 一次能够发送多个【不用停止等待,一次只能发一个】
    • 每一个的应答都有:ACK,NAK;麻烦
    • 使用对前一个数据单位的ACK,代替本数据单位的NAK
    • 确认信息减少一半,协议处理简单

NAK free

rdt2.2的运行

当ack出错,就重发当前packet,接收方通过packet编号能够检测重复否,重复了就扔了,扔了之后再给一个ack+当前分组编号(这里就是ack0),使得发送方再发一个packet1,双方又重新回到一个同步状态

rdt2.2:发送方和接收方片段

【只有红色部分和rdt2.1不一样,这里用ACK1代表NAK,用ACK0代表ACK,接收方也是这样】

rdt3.0:具有比特差错和分组丢失的信道

新的假设:下层信道可能会丢失分组(数据或ACK)【分组丢失:路由器有队列,来了分组排队列,当等待队列满了的话就会丢掉】

  • 会死锁【如果分组丢失,没有任何一个机制的话就会死锁,发送方在等确认,接收方在等新的分组】【就需要一个新的机制,叫超时重传机制】
  • 机制还不够处理这种状况:
    • 检验和
    • 序列号
    • ACK
    • 重传

方法:发送方等待ACK一段合理的时间(链路层的timeout时间确定的、传输层timeout时间是适应式的)

  • 发送端超时重传:如果到时没有收到ACK->重传【超时时间:正常往返多一点的时间】
  • 问题:如果分组(或ACK)只是被延迟了:
    • 重传将会导致数据重复,但利用序列号已经可以处理这个问题
    • 接收方必须指明被正确接受的序列号
  • 需要一个倒计数定时器

rdt3.0 发送方

来了data,0号,checksum计算形成分组放出去,start_timer启动超时定时器。在等待的时候如果超时定时器启动了,就把刚刚形成的分组重放一遍,重放之后仍然要启动一个超时定时器。另外是等待ack0号确认的时候,收到的ack0不知道是啥,要重发packet0;还有一个等待ack0确认的时候收到的是ack1,等待超时定时器启动重发分组。

超时定时器在发送方放完一个分组之后要启动,在发送方等待确认的时候,超时事件启动之后要把刚刚形成的分组重放一遍,仍然再启动超时定时器;在等待ack0的时候收到ack1 or 在等待ack1的时候收到ack0,这时候说明发出去的分组出错了(没通过校验),没有直接重放一遍刚刚的分组,而是等待超时事件启动,然后再把刚刚的分组重放一遍,然后这时候仍然需要把超时定时器启动

rdt3.0的运行

【超时时间设置要比正常往返事件要多,多3倍、4倍…∑方差,这样的话能够确保要是服从正态分布的话,在期望+4倍方差,这样能保证在99.多%的概率一定是丢失掉的】

  • 过早超时(延迟的ACK)也能够正常工作;但是效率较低,一半的分组和确认是重复的
  • 设置一个合理的超时时间也是比较重要的

rdt3.0的性能

  • rdt3.0可以工作,但链路容量比较大的情况下,性能很差【在信道容量比较大的情况下效率比较低;每个比特持续时间1/R,往返延迟÷1/R = 整个信道能够容纳比特的个数;发送一个分组(全部发出后),分组的第一个比特离接收方还很远,把这种情况称为信道比较大;如果信道只允许一个分组发完之后再发下一个分组,那说明信道利用率非常低】
    • 链路容量比较大,一次发一个PDU的不能够充分利用链路的传输能力

【单向的传播延迟:t = 15ms,双向的RTT = 2t = 30ms,一个分组发送需要L / R = 1KB / 1Gbps = 1000bits / 10^9bps = 0.008μs,利用率(L/R)/(RTT + L/R) = 0.00027;有效的吞吐 1Gbps * 0.00027 = 270kbps】

【整个吞吐的瓶颈问题在于协议本身,协议规定一次只发一个分组】

rdt3.0:停-等操作

流水线:提高链路利用率

需要好几倍编号才能表示不同的分组;一次发三个利用率就增加了三倍。不能无限制的增加,增加到利用率合适的时候瓶颈就是最短的那个板了(短板效应)了。

停等协议在链路容量比较小的时候,一次发一个

停等协议在链路容量比较大的时候就需要一次发送多个未经确认的分组,而且需要对分组做一个长比特的编号,这样才能区分不同的分组,我们把这种一次发送多个分组的协议叫做pipeline协议(流水线协议)

流水线协议

流水线:允许发送方在未得到对方确认的情况下一次发送多个分组

  • 必须增加序号的范围:用多个bit表示分组的序号
  • 在发送方/接收方要有缓冲区【发送方发送完毕之后从,把分组保持在缓冲区当中,以便于检错重发或者是超时重发,在接收端要有一个缓冲区的目的是发送方发送的速率和接收方收到的速率可能不一样,需要一个缓存来对抗速度的不一致性】
    • 发送方缓存:未得到确认,可能需要重传
    • 接收方缓存:上层用户取用数据的速率 ≠ 接收到的数据速率;接收到的数据可能乱序,排序交付(可靠)

  • 两种通用的流水线协议:回退N步(GBN)选择重传(SR)

通用:滑动窗口(slide window)协议【一般性协议】

【如果sending window = 1,receiving window = 1的时候,就是停等协议(rdt3.0)】

【如果sending window > 1,receiving window = 1的时候,就是GBN协议(流水线协议)】

【如果sending window > 1,receiving window > 1的时候,就是SR协议(流水线协议)】

  • 发送缓冲区
    • 形式:内存中的一个区域,落入缓冲区的分组可以发送
    • 功能:用于存放已发送,但是没有得到确认的分组
    • 必要性:需要重发时可用
  • 发送缓冲区的大小:一次最多可以发送多少个未经确认的分组
    • 停止等待协议 = 1
    • 流水线协议 > 1,合理的值,不能很大,链路利用率不能够超100%
  • 发送缓冲区中的分组【如果缓冲区没用完,剩下的空间发送方上层用户可以接着往下交分组,从而封装分组,向外面进行分组的发送】
    • 未发送的:落入发送缓冲区的分组,可以连续发送出去;
    • 已经发送出去的、等待对方确认的分组:发送缓冲区的分组只有得到确认才能删除

发送窗口滑动过程-相对表示方法

  • 采用相对移动方式表示,分组不动
  • 可缓冲范围移动,代表一段可以发送的权力

【绿色的范围代表发送缓冲区的范围,白色代表可发但是还没发送的范围,红色代表已发送但没得到确认的范围,绿色代表已经收到确认的范围】

【真正的滑动过程——发送缓冲区不动,分组在移动】

【为了便于学习和表示,采用相对滑动的方式——分组不动,发送缓冲区在向前移动】

滑动窗口(slide window)协议

  • 发送窗口:发送缓冲区内容的一个范围【发送缓冲区的一个子集】
    • 那些已发送但是未经确认分组的序号构成的空间【如果除了发送窗口,发送缓冲区还有空间,如果上层用户还有分组需要发送,实际上可以把它发生出去】
  • 发送窗口的最大值 <= 发送缓冲区的值
  • 一开始:没有发送任何一个分组
    • 后沿 = 前沿
    • 之间为发送窗口的尺寸 = 0
  • 每发送一个分组,前沿前移一个单位

发送窗口的移动 -> 前沿移动

  • 发送窗口前沿移动的极限:不能够超过发送缓冲区

发送窗口的移动 -> 后沿移动

  • 发送窗口后沿移动
    • 条件:收到老分组(后沿)的确认
    • 结果:发送缓冲区罩住新的分组,来了分组可以发送
    • 移动的极限:不能够超过前沿

滑动窗口(slide window)协议——发送窗口

  • 滑动窗口技术
    • 发送窗口(sending window)

滑动窗口(slide window)协议——接收窗口

  • 接收窗口(receiving window) = 接收缓冲区
    • 接收窗口用于控制哪些分组可以接收
      • 只有收到的分组序号落入接收窗口内才允许接收
      • 若序号在接收窗口之外,则丢弃
    • 接收窗口尺寸Wr = 1,则只能顺序接收【GBN协议】
    • 接收窗口尺寸Wr > 1,则可以乱序接受【SR协议】
      • 但提交给上层的分组,要按序

🔸例子:Wr = 1,在0的位置;只有0号分组可以接收;

向前滑动一个,罩在1的位置,如果来了第2号分组,则丢弃【第一个动作:丢弃掉2号分组,第二个动作:给顺序到来的最高分组的确认ack0】

  • 接收窗口的滑动和发送确认
    • 滑动:
      • 低序号的分组到来,接收窗口移动
      • 高序号分组乱序到,缓存但不交付(因为要实现rdt,不允许失序),不滑动
    • 发送确认:
      • 接收窗口尺寸 = 1;发送连续收到的最大的分组确认(累计确认)
      • 接收窗口尺寸 > 1;收到分组,发送那个分组的确认(非累计确认)

🔸例子:Wr > 1

【低序号的分组到来,接收窗口移动】

【高序号分组乱序到,缓存但不交付(因为要实现rdt,不允许失序),不滑动】

【接收方收到1,2分组,这时候要给出1,2号分组的确认,但是因为0号分组没有到来,所以接收方不可以做接收窗口的向前滑动。再收到0号分组,要给对方发一个ack0的确认,同时由于0,1,2号分组都已经到来,因此可以把分组当中的数据解封装出来,一起有序地交给上面用户,然后整个接收窗口向前滑动3格】

【Wr = 1,对顺序到来的最高序号的分组的确认;Wr > 1,收到哪个分组就给哪个分组确认(序号在接受窗口之内的,序号在接收窗口之外的就会丢弃),独立确认】

正常情况下的2个窗口互动

【真正的源动力在于发送方的上层用户不断地向前发】

异常情况下GBN的2窗口互动

【异常情况:传输的分组在过程中出错或者丢失、接收方给的确认没有到达发送方】

超时肯定是后沿分组先超时,超时带来的一个动作是把发送窗口当中所有已发送但是未确认的分组都重新再放送一遍

异常情况下SR的2窗口互动

【发送方未收到确认的分组的超时定时器会超时,这时候超时重发机制会让发送方重发未收到确认的分组,而收到确认的其他分组是不重新发送的

【SR协议一次可以发送多个未经确认的分组,而且每发送一个分组,发送方就要启动一个超时定时器,哪个超时定时器到时,发送方就单独发那一个分组;每收到一个分组的确认就要把超时定时器关掉】

【接收方每收到接收窗口之内的分组,就要给出这个分组的单独的一个分组的确认】

GBN协议和SR协议的异同

  • 相同之处【都是流水线协议(管道协议)】
    • 发送窗口 > 1
    • 一次能够发送多个未经确认的分组【发送方在没有得到对方确认的情况下可以发送很多个未经确认的分组】
  • 不同之处
    • GBN:接收窗口尺寸 = 1
      • 接收端:只能顺序接收【对于乱序到来的分组丢弃】
      • 发送端:从表现来看,一旦一个分组没有发成功,如:0,1,2,3,4;假设1未发成功,234都发送出去了,要返回1再重发所有已发但是没有收到确认的分组;GB1
    • SR:接收窗口尺寸 > 1
      • 接收端:可以乱序接收
      • 发送端:发送0,1,2,3,4,一旦1未成功,2,3,4已发送,无需重发,选择性发送1

流水线协议:总结

Go-back-N

  • 发送端最多在流水线中有N个未确认的分组
  • 接收端只是发送累计型确认cumulative ack
    • 接收端如果发现gap,不确认新到来的分组
  • 发送端拥有对最老的未确认分组的定时器
    • 只需设置一个定时器
    • 当定时器到时时,重传所有未确认分组

Selective Repeat

  • 发送端最多在流水线中有N个未确认的分组
  • 接收方对每个到来的分组单独确认individual ack(非累计确认)
  • 发送方为每个未确认的分组保持一个定时器
    • 当超时定时器到时,只是重发到时的未确认分组

GBN:发送方扩展的FSM

初始化进入到等待状态,base就是发送窗口的后沿,nextseqnum是发送窗口的前沿-1,nextseqnum - base就是发送窗口的范围,现在发送窗口=0意味着没有已发但未确认的分组,初始化=1意味着发送方要从第一号分组开始传。如果这时候来了事件,上层有数据需要发送,如果这个分组nextseqnum落在base + N,N是缓冲区大小,落在可发送的范围之内,nextseqnum,数据,chksum计算出来,形成这个分组,通过下层接口把分组放出去(udt_send(sndpkt[nextseqnum]));如果在发送之前base == nextseqnum,意味着发送窗口的大小等于0,这时候超时定时器没有启动,就需要启动超时定时器,nextseqnum++就是前沿滑动,如果在发送缓冲区以外就没办法发送分组,因为发送缓冲区已经用完了。如果超时定时器超时了,一定是最老的那个分组超时了,那么发送方将发送窗口当中的已发送但是未收到确认的分组都重新发送。如果这时候发送方收到确认分组,将确认分组ack的序号取出+1赋给base(base = getacknum(rcvpkt)+1),这是一个后沿向前滑动的一个动作,如果加完之后base == nextseqnum,这时候发送窗口是没有已发送但未确认的分组了,这时候超时定时器要把它关掉,否则的话重新启动超时定时器。如果确认分组出错就等待超时启动。

GBN:接收方扩展的FSM

【初始化进入等待的状态,在GBN协议下,接收窗口大小等于1,因此可以用一个变量来维护接收窗口罩在什么样的位置,expectedseqnum=1也就意味着接收窗口从第一号分组开始接收,一开始罩在1的位置上,而且做好了对一号分组的确认,但是还没发。如果在等待的状态下,接收方收到一个数据分组,而且这个分组通过了差错控制编码的校验没有出错,而且来了分组的序号和我正在等待分组的序号是一样的,要做的第一个动作就是解封装,通过层间的接口往上交,然后再形成对当前分组的确认,通过下层的接口把分组的确认发出去,然后expectedseqnum++,接收窗口向前滑动】

  • 只发送ACK:对顺序接收的最高序号的分组
    • 可能会产生重复的ACK
    • 只需记住expectedseqnum;接收窗口 = 1
      • 只一个变量就可表示接收窗口
  • 对乱序的分组
    • 丢弃(不缓存) -> 在接受方不被缓存!
    • 对顺序接收的最高序号的分组进行确认 - 累计确认

【需要接收5号分组,但是传来的是6号分组,就丢弃,然后给发送方发ack4,顺序接受的最高序号的分组进行确认】

运行中的GBN

选择重传SR

  • 接收方对每个正确接收的分组,分别发送ACKn(非累计确认)
    • 接收窗口 > 1
      • 可以缓存乱序的分组
    • 最终将分组按顺序交付给上层
  • 发送方只对那些没有收到ACK的分组进行重发-选择性重发
    • 发送方为每个未确认的分组设定一个定时器
  • 发送窗口的最大值(发送缓冲区)限制发送未确认分组的个数

选择重传

发送方

从上层接收数据:

  • 如果下一个可用于该分组的序号可在发送窗口中,则发送【从上面收到数据,如果在发送缓冲区之内,就形成分组发出去】

timeout(n):

  • 重新发送分组n,重新设定定时器【哪个分组超时就发生哪个分组】

ACK(N) in [sendbase, sendbase+N]

  • 将分组n标记为已接受
  • 如n为最小未确认的分组序号,将base移到下一个未确认序号

接收方

分组n [rcvbase, rcvbase+N-1]

  • 发送ACK(n)
  • 乱序:缓存
  • 有序:该分组及以前缓存的序号连续的分组交付给上层,然后将窗口移到下一个仍未被接收的分组【解封装、交给上层、移动接收窗口】

分组n [rcvbase-N, rcvbase-1]

  • ACK(n)

其他:

  • 忽略该分组

选择重传SR的运行

对比GBNSR

GBN

SR

优点

简单,所需资源少(接收方一个缓存单元)

出错时,重传一个代价小

缺点

一旦出错,回退N步代价大

复杂,所需资源多(接收方多个缓存单元)

  • 适用范围
    • 出错率低:比较适合GBN,出错非常罕见,没有必要用复杂的SR,为罕见的事件做日常的准备和复杂处理
    • 链路容量大(延迟大、带宽大):比较适合SR而不是GBN,一点出错代价太大

窗口的最大尺寸

n个比特代表分组序号;GBN发送窗口的最大值2^n - 1,SR发送窗口的最大值是2^(n - 1)

  • 12
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值