我们都知道 TCP 协议是一种可靠的传输层协议,它可以保证 HTTP 报文无差错、无损失且有序地从客户端到达地服务器,那么这种可靠性是怎么实现的呢?
可靠数据传输的实现不仅在传输层出现,也会在链路层以及应用层出现,在计算机网络中,这个问题显得尤为重要,首先我们来看下,例如 TCP 所采用的许多原理,就是基于这个可靠数据传输的,请看下图:
可靠数据传输就是为上层试题提供的服务抽象是提供数据通过一条可靠的信道进行传输,借助于可靠信道,传输数据比特就不会受到损坏或者丢失,而且所以数据都是按照其发送顺序进行交付。
由于可靠数据传输协议的下层协议也许是不可靠的,例如 TCP 是在不可靠的 IP 端到网络层之上实现的可靠数据传输协议。
构建可靠数据传输协议
在接下来文章中我们将一步步地研究一系列协议,它们一个比一个更为复杂,最后得到一个完美、可靠的数据传输协议。
完全可靠信道的数据传输: rdt1.0
首先我们考虑最简单的情况,即底层信道是一个完全可靠的,我们称该协议为 rdt1.0,该协议本身是简单的。
rdt1.0 发送方和接收方各持有一个 有限状态机(FSM) 的定义,它们每个都只有一个状态,因此变迁必定是从一个状态返回到自身。
发送端通过 rdt_send(data) 事件接受来自较高层的数据产生一个包含该数据的分组,并将分组发送到信道中,实际上,rdt_send(data) 事件由较高层应用的过程调用产生的。
在接收端通过 rdt_rcv(packet) 事件从底层信道接受一个分组,从分组中取出数据,并将数据上传到较高层。实际上 rdt_rcv(packet) 事件是由较低层协议的过程调用产生的。
在这个简单的协议中,一个单元数据与一个分组没差别,而且所有分组是从发送方流向接收方,有了完全可靠的信道,接收端就不需要提供任何反馈信息给发送方,因为不必担心出现差错。
具有比特差错信道的可靠数据传输: rdt2.0
在开始本节内容之前,我们先来考虑一下人们会怎样处理这类的情绪。考虑一下你自己是怎样通过电话口述的一条长报文的,在通常情况下,报文接收者会在听到、理解并记下每句话后会说 OK。如果报文接收者听到一句含糊不清的话时,他可能要求你重复那句容易误解的话,这种口述报文协议使用了肯定确认(ack)和否定确认(nak)。
这些控制报文是的接收方可以让发送方知道哪些内容被正确接收,哪些内容接收有误并因此需要重复,在计算机网络环境中,基于这样重传机制的可靠数据传输协议称为自动重传请求 ARQ 协议。
相比于 rdt1.0,它新增三种协议功能来处理存在比特差错的情况:
差错检测;接收方反馈;重传;
下图说明了表示 rdt2.0 的有限状态机,该数据传输协议采用了差错检测、肯定确认与否定确认:
rdt2.0 的发送端有两个状态,在最左边的状态中,发送端协议正等待来自上层传下来的数据,当 rdt_send(data) 事件出现时,发送方将产生一个包含待发送数组的分组,带有校验和,然后经由 udt_send(sndpkt) 操作发送该分组,在最右边的状态中发送方协议等待来自接收方的 ACK 或 NAK 分组。
如果接收到一个 ACK 分组,则发送发知道最近发送的分组已被正确接收,因此协议返回到等待来自上层的数据的状态,如果接收到一个 NAK 分组,该协议重传上一个分组并等待接收方为响应重传分组而回送的 ACK 和 NAK。
当发送方处于等待 ACK 或 NAK 的窗台时,它不能从上层获得更多的数据,这就是说,rdt_send 事件不可能出现,仅当接收到 ACK 并离开该状态时才能发送这样的事件,发送方将不会发送一块新数据,除非发送方确信接收方已正确接收当前分组,这种协议被称为 停等 协议。
这个看起来似乎可以运行了,但遗憾的是,它存在一个致命的缺陷,尤其是我们没有考虑到 ACK 或者 NAK 分组受损的可能性,如果一个 ACK 或者 NAK 分组受损,发送方无法知道接收方是否正确接收了上一块发送的数据。
为了解决这个问题, rdt2.1 就应运而生了,它主要做的事情就是在分组当中加序号,加序号的目的是接收方只需要检查序号即可接收到分组是否需要重传。
发送方和接收方的有限状态机的状态数都是以前的两倍。
rdt2.1 的具体流程就是发送方发送一个序号为 0 的分组,进入等待 ack 或者 nak 的状态,若接收到 nak 或者确认信息损坏就重传分组,如果接收到 ack 却确认消息未损坏,则改变序列号为 1,但是考虑到接收方接收到 0 号数据包,返回 ack 但是 ack 受损,接收方重复发送 0 号数据,接收方会丢掉 0 号数据,因为前面已经接收到数据了,避免重复。
rdt2.2 没啥好讲的,就是在 rdt2.1 的基础上去掉 nak,给 ack 添加序列号,具体流程如下图所示:
这个时候说明 p0 分组正确,而 p1 分组需要重传。
经具有比特差错的丢包信道的可靠数据传输: rdt3.0
现在假定除了比特受损外,底层信道还会丢包,这在今天的计算机网络中并不罕见。
假定发送方传输一个数据分组,该分组或者接收方对该分组的 ACK 发生了丢失,在这两种情况下,发送方都接收不到应到来的接收方的响应,这样就形成一个死锁了,接收方不知道没有收到发送方的信息,一直在等,相反亦是如此。
从发送方的观点来看,重传是一种万能灵药,发送方不知道是一个数据分组丢失,还是一个 ACK 丢失,或者只是该分组或 ACK 过度延时,在所有的这些情况下,动作是同样的:重传,为了实现基于事件的重传机制,需要一个倒计数定时器,在一个给定的时间量过期后,可中断发送方,因此发送方需要能做到:
- 每次发送一个分组,包括第一次分组和重传分组,边启动一个定时器;
- 响应定时器终端;
- 终止定时器;
因为分组序号在 0 和 1 之间交替,因此 rdt3.0 有时被称为比特交替协议。
流水线可靠数据传输协议
rdt3.0 是一个功能正确的协议,但并非人人都对它的性能满意,它存在性能问题的核心在于它是一个停等协议。
这种特殊的性能问题的一个简单的解决方法是:不以停等方式运行,允许发送方发送多个分组而无须等待确认,,如果发送方等待确认之前发送三个报文,其利用率也基本上提高三倍。因为许多从发送方向接收方输送的分组可以被看成是填充到一条流水线中,这种技术被称为流水线,流水线技术对可靠数据传输协议可带来如下影响:
要实现这个问题,必须考虑以下几个问题:
- 增加序号范围,因为每个输送中的分组必须有一个唯一的序号,而且也许有多个输送中未被确认报文;
- 协议的发送方和接收方两端也许不得不缓存多个分组,发送方最低限度应当能缓冲那些已经发送但没有确认的分组,接收方或许也需要缓存那些已正确接收的分组;
- 所需序号范围和缓冲的要求取决于数据传输协议如何处理丢失、损坏及延时过大的分组,解决流水线的差错挥霍两种基本方法是: 回退
N步 和选择重传;
好了,本篇文章内容到此告一段落,在下一篇文章中将会讲解回退N步和选择重传
参考文献
- 书籍:
计算机网络自顶向下方法原书第七版;