可靠数据传输基本原理

2019-05-25 19:50:10 浏览数 (1)

版权声明:本文为博主原创文章,转载请注明博客地址: https://cloud.tencent.com/developer/article/1433281

可靠数据传输是指:数据可以通过一条可靠信道来传输。传输的数据不会受到损失或者丢失,而且所有数据都是按照其发送顺序进行交付。

我们都知道IP层是不可靠传输的,而TCP是可靠传输的,但是TCP是传输层的协议,这就要求设计一个合理的协议机制,当底层丢失的时候,需要如何处理。下面一步步构造可靠数据传输协议。称之为rdt协议。

rdt1.0

在rdt1.0中,我们先考虑一个最简单的情况,即底层信道是完全可靠的。当然,现实中没有完全可靠的信道,因为信息在传输的过程中有噪声影响(引起误差),并且信道容量需要遵循香农公式(引起丢失),一旦信息超过了信道容量,那么信息一定会有丢失。

我们来使用有限状态机(FSM)来描述接收方和发送放的状态变化。如下图所示:

FSM描述图中的箭头指示来一个协议从一个状态变迁到另一个状态。引起变迁的事件写在横线的上方,事件发生时采取的动作写在下方。虚线表示初始状态。上图中的接收方和发送方都只有一个状态。

rdt_send()事件接受上层的数据,产生一个分组(使用make_pkt()产生).,并且发送到信道中。

rdt_rcv()事件从底层信道接受一个分组。从分组中取出数据(extract()来完成),并将数据传输到较高层。

我们还需要假定接收方和发送方的数据传输速率是一致的。

有了这些,所有的分组都是经过这条可靠信道传输的,完全不用担心会出现差错,因此,接受方也无需给发送方返回任何信息。这样,可靠传输就完成了。

rdt2.0

在rdt2.0中,我们假设底层信道是只具备“比特可能受损”的特性。按照通信原理的内容具体来看,就是指在传输过程中的误码或者是误信率。

正如我们日常生活中一样,数据错误的时候需要重新发送,在rdt2.0中采用的是自动重传协议(ARQ),一旦出现错误,那么可靠数据传输协议就会自动重传数据。当然,我们需要确定什么时候需要重传,如何告诉发送方,重传。因此,rdt2.0相比于1.0版本而言,增加了一下机制:

  1. 差错检测
  2. 接收方反馈
  3. 重传

差错检测可以使用检验和,接收方反馈的情况无非就是“肯定确认”(ACK)和“否定确认”(NAK)。当发送方接收到接收方反馈回来的NAK消息时,发送方重传该分组。

发送方有两个状态,分别是等待上层传下来的数据以及等待接收方反馈回来的消息。当上层传输下来数据后,就调用rdt_send()发送数据。然后进入等待接收方反馈消息的状态。如果反馈的是ACK,那么说明数据无误,进入等待上层数据状态;如果反馈消息是NAK,那么重发分组,并且继续等待接收方的反馈消息,直到等到ACK消息,才进入等待上层数据状态。需要注意,在这种情形下,不能在等待ACK和NAK的时候从上层获取数据。称之为“停等”协议。

接收方在rdt2.0中仍旧只有一个状态,当数据到达之后,计算校验和,然后反馈给发送方ACK或者NAK。

rdt2.0协议的致命缺陷是没有考虑到NAK和ACK分组可能会受损。

解决这个问题的一个简单办法给分组中添加一个新字段:编号。即把发送数据分组的序号放在该字段。这样,接收方只需要检测序号就能发现是否重传了分组。rdt2.0是“停等”的,因此,只需要一位序号就够了。因为只有接收方和发送方都确认该分组传输完成了,才会传输下一个分组。只要前后两次分组的编号是不同的即可,不需要管分组编号是否重复。

发送方

接收方的状态也有4种,它反映出了希望接受的分组是0还是1。需要注意的是当接收方接收到的分组是失序的(也就是它正确接受了上一个分组),它返回ACK,当然也必须这样返回,因为这就是出现了第一次返回ACK受损。

如果序号正确,但是分组受损,那么返回一个NAK消息。如果不返回NAK,而是返回对上一个正确接受分组的ACK,这也能实现一样的效果。因为发送方收到以后就知道,你没有成功接受上一个分组之后的分组。也就是说,接收方只返回ACK即可,如果返回的ACK中的编号是发送方刚才发送的,那么说明接收正确;如果返回的ACK的编号是上次发送方上一次发送的数据编号,那么说明接受错误。

接收方

经过上面的改造就形成了rdt2.1版本,此时我们的信道仍旧是只具备“比特可能受损”的特性。

rdt3.0

在rdt2.0中,我们假设的信道模型是只具备“比特可能受损”的特性。这距离真实的信道模型仍旧有一些差距。现在在rdt3.0中,我们假设信道模型是“即可能发生传输误差,也可能产生丢失”。这样就基本和实际是相符的。

那么在rdt3.0中存在的新问题就是如何解决丢失的数据的重传问题,其他的问题在rdt2.0中就已经解决了。

一个实际情况可能是发送方发送数据,在信道传输的过程中丢失了(其中最重要的丢失原因就是,路由器缓存溢出了)。那么接收方只能等待(不做任何反应)。我们的解决方案是“发送方在一个合理的时间内等待ACK”。如果一旦超出这个时间还没有收到ACK,那么发送方就重传;但是如果接收方收到了数据,但是ACK在途中丢失了,这也会导致发送方重传,这样数据就会重复,这个问题在rdt2.0中由“编号”已经解决了。问题的难点是如何把握一个“合理的时间”,这个时间的长短选取才是问题的难点所在。

发送方状态机

我们在rdt3.0中引入了定时器,它来帮助我们解决丢失重传。到此为止,rdt3.0基本上解决了传输过程中出现差错的问题以及丢失问题。但是rdt3.0的性能很差,这是由于它是一个“停等”协议。它需要停下来等待接收方返回的ACK。下面这个示例表明了问题的严重性。

也就是下图中的往返时间RTT占据的时间太长了,正如上面的示例,8微秒发送,但是RTT确长达30ms。

到此为止,rdt3.0看起来能用了,但是实际上仍旧无法实际实现。革命尚未成功,同志仍需努力。

在下一篇中,我们解决了这个性能底下的问题。

0 人点赞