运输层 可靠数据传输原理——1、构造可靠数据传输协议

概述      

  在本文中,我们讨论在通常情况下可靠数据传输的问题。因为可靠数据传输的实现问题不仅在运输层出现,也会在链路层以及应用层出现。一般性问题对网络来说更为重要。

下图图示说明了我们学习可靠数据传输的框架。为上层实体提供的服务抽象是:数据可以通过一条可靠的信道进行传输。借助于可靠信道,传输数据比特就不会受到损坏(由0变为1,或者相反)或丢失,而且所有数据都是按照其发送顺序进行交付。这恰好就是 TCP向调用它的因特网应用所提供的服务模型。

        实现这种服务抽象是可靠数据传输协议(reliable data transfer protocol)的责任。由于可靠数据传输协议的下层协议也许是不可靠的,因此这是一项困难的任务。例如,TCP是在不可靠的(IP)端到端网络层之上实现的可靠数据传输协议。更一般的情况是,两个可靠通信端点的下层可能是由一条物理链路(如在链路级数据传输协议的场合下)组成或是由一个全球互联网络(如在运输级协议的场合下)组成。然而,就我们的目的而言,我们可将较低层直接视为不可靠的点对点信道

        考虑到底层信道模型越来越复杂,我们将不断地开发一个可靠数据传输协议的发送方和接收方。例如,我们将考虑当底层信道能够损坏比特或丢失整个分组时,需要什么样的协议机制。这里贯穿我们讨论始终的一个假设【前提】是分组将以它们发送的次序进行交付,某些分组可能会丢失 : 这就是说,底层信道将不会对分组重排序。图 b图示说明了用于数据传输协议的接口。通过调用rdt_send()函数,可以调用数据传输协议的发送方。它将要发送的数据交付给位于接收方的较高层。(这里rdt表示可靠数据传输协议,_send指示rdt的发送端正在被调用。开发任何协议的第一步就是要选择一个好的名字!)在接收端,当分组从信道的接收端到达时,将调用rdt_rcv()。当rdt协议想要向较高层交付数据时,将通过调用deliver_data()来完成。后面,我们将使用术语“分组”而不用运输层的“报文段”。因为本文研讨的理论适用于一般的计算机网络,而不只是用于因特网运输层,所以这时采用通用术语“分组” 更为合适。

        在本文中,我们仅考虑单向数据传输(unidirectional data transfer)的情况,即数据传输是从发送端到接收端的。可靠的双向数据传输(bidirectional data transfer)(即全双工数据传输)情况从概念上讲不会更难,但解释起来更为单调乏味。虽然我们只考虑单向数据传输,注意到下列事实是重要的,我们的协议也需要在发送端和接收端两个方向上传输分组,如上图所示。我们很快会看到,除了交换含有待传送的数据的分组之外,rdt的发送端和接收端还需往返交换控制分组。rdt的发送端和接收端都要通过调用udt_send()发送分组给对方(其中udt表示不可靠数据传输)。

        我们一步步地研究一系列协议,它们一个比一个更为复杂,最后得到一个无错、可靠的数据传输协议。

1、经完全可靠信道的可靠数据传输:rdt1.0

        首先,我们考虑最简单的情况,即底层信道是完全可靠的。我们称该协议为rdt1.0,该协议本身是简单的。图下显示了rdt 1.0发送方和接收方的有限状态机(Finite-State Machine,FSM)的定义。图 a中的FSM定义了发送方的操作,图 b中的FSM定义了接收方的操作。注意到下列问题是重要的,发送方和接收方有各自的FSM。全图 中发送方和接收方的FSM每个都只有一个状态。FSM描述图中的箭头指示了协议从一个状态变迁到另一个状态。(因为 全图 中的每个FSM都只有一个状态,因此变迁必定是从一个状态返回到自身) 引起变迁的事件显示在表示变迁的横线上方事件发生时所采取的动作显示在横线下方。如果对一个事件没有动作,或没有就事件发生而采取了一个动作,我们将在横线上方或下方使用符号Δ,以分别明确地表示缺少动作或事件。FSM的初始状态用虚线表示。尽管全图中的FSM只有一个状态,但文章下面我们就将看到多状态的FSM,因此标识每个FSM的初始状态是非常重要的。

        rdt的发送端只通过rdt_send(data)事件接受来自较高层的数据,产生一个包含该数据的分组(经由make_pkt(data)动作),并将分组发送到信道中。实际上,rdt_send(data)事件是由较高层应用的过程调用产生的(例如,rdt_send())。

        在接收端,rdt通过rdt_rcv(packet)事件从底层信道接收一个分组,从分组中取出数据(经由extract(packet,data)动作),并将数据上传给较高层(通过 deliver_data(data)动作)。实际上,rdt_rcv(packet)事件是由较低层协议的过程调用产生的(例如,rdt_rcv())。 在这个简单的协议中,一个单元数据与一个分组没差别。而且,所有分组是从发送方流向接收方;有了完全可靠的信道,接收端就不需要提供任何反馈信息给发送方,因为不必担心出现差错!注意到我们也已经假定了接收方接收数据的速率能够与发送方发送数据的速率一样快。因此,接收方没有必要请求发送方慢一点!

2.经具有比特差错信道的可靠数据传输:rdt2.0

        底层信道更为实际的模型是分组中的比特可能受损。在分组的传输、传播或缓存的过程中,这种比特差错通常会出现在网络的物理部件中。我们眼下还将继续假定所有发送的分组(虽然有些比特可能受损)将按其发送的顺序被接收

        在研发一种经这种信道进行可靠通信的协议之前,首先考虑一下人们会怎样处理这类情形。向一下你自己是怎样通过电话口述一条长消息的。在通常情况下,报文接收者在听到、理解并记下每句话后可能会说“OK”。如果报文接收者听到一句含糊不清的话时他可能要求你重复刚才那句话。这种口述报文协议使用了肯定确认(positve acknowledgment)(“OK”)与否定确认(negative acknowledgment)(“请重复一遍”)。这些控制报文使得接收方可以让发送方知道哪些内容被正确接收、哪些内容接收有误并因此需要重复。在计算机网络环境中,基于这样重传机制的可靠数据传输协议称为自动重传请求(Auomatic Repeat reQuest,ARQ)协议

基本上,ARQ协议中还需要另外三种协议功能来处理存在比特差错的情况:

  1. 差错检测。首先,需要一种机制以使接收方检测到何时出现了比特差错。前一节讲到,UDP使用因特网检验和字段正是为了这个目的。在第5章中,我们将更详细地学习差错检测和纠错技术。这些技术使接收方可以检测并可能纠正分组中的比特差错。此刻,我们只需知道这些技术要求有额外的比特(除了待发送的初始数据比特之外的比特)从发送方发送到接收方;这些比特将被汇集在rdt2.0数据分组的分组检验和字段中。
  2. 接收方反馈。因为发送方和接收方通常在不同端系统上执行,可能相隔数千英里发送方要了解接收方情况(此时为分组是否被正确接收)的唯一途径就是让接收方提供明确的反馈信息给发送方。在口述报文情况下回答的“肯定确认”(ACK)和“否定确认”(NAK)就是这种反馈的例子。类似地,我们的rdt2.0协议将从接收方向发送方回送ACK与NAK分组。理论上,这些分组只需要一个比特长:如用0表示NAK,用1表示ACK。
  3. 重传。接收方收到有差错的分组时、发送方将重传该分组文。

下图 说明了表示rdt 2.0的FSM,该数据传输协议采用了差错检测、肯定确认与否定确认。

        rdt2.0的发送端有两个状态。在最左边的状态中,发送端协议正等待来自上层传下来的数据。当产生rdt_send(data)事件时,发送方将产生一个包含待发送数据的分组(sndpkt)带有检验和(例如,就像对UDP报文段使用的方法——发送方的UDP对报文段中的所有16比特字的和进行反码运算求和时遇到的任何溢出都被回卷。得到的结果被放在UDP报文段中的检验和字段。)【如果不清楚,看我相关的文章即可,有详细介绍】,然后经由udt_send(sndpkt)操作发送该分组。在最右边的状态中,发送方协议等待来自接收方的ACK或NAK分组。如果收到一个ACK分组(上图 中符号rdt_rcv(rcvpkt)&&isACK(rcvpkt)对应该事件),则发送方知道最近发送的分组已被正确接收,因此协议返回到等待来自上层的数据的状态。如果收到一个NAK分组,该协议重传最后一个分组并等待接收方为响应重传分组而回送的ACK和NAK注意 ,下列事实很重要 : 当发送方处于等待ACK或NAK的状态时,它不能从上层获得更多的数据; 这就是说,rdt_send()事件不可能出现; 仅当接收到ACK并离开该状态时才能发生这样的事件。因此,发送方将不会发送一块新数据,除非发送方确信接收方已正确接收当前分组。由于这种行为, rdt 2.0这样的协议被称为停等(stop-and-wait)协议。

        rdt 2.0接收方的FSM仍然只有一个状态。当分组到达时,接收方要么回答一个ACK,要么回答一个NAK,这取决于收到的分组是否受损。在 上图 中,符号rdt_rev(rcvpkt)&&corrupt(rcvpkt)对应于收到一个分组并发现有错的事件。

        rdt2.0协议看起来似乎可以运行了,但是,它存在一个致命的缺陷。尤其是我们没有考虑到ACK或NAK分组受损的可能性!(在继续研究之前,你应该考虑怎样解决该问题。)遗憾的是,我们细小的疏忽并非像它看起来那么无关紧要。至少,我们需要在ACK/NAK分组中添加检验和比特以检测这样的差错。更难的问题是协议应该怎样纠正ACK或NAK分组中的差错。这里的难点在于,如果一个ACK或NAK分组受损,发送方无法知道接收方是否正确接收了上一块发送的数据。

考虑处理受损ACK和NAK时的3种可能性:

  1. 对于第一种可能性,考虑在口述报文情况下人可能的做法。如果说话者不理解来自接收方回答的“OK”或“请重复一遍”,说话者将可能问“你说什么?”(因此在我们的协议中引入了一种新型发送方到接收方的分组)。接收方则将复述其回答。但是如果说话者的“你说什么?”产生了差错,情况又会怎样呢?接收者不明白那句混淆的话是口述内容的一部分还是一个要求重复上次回答的请求,很可能回一句“你说什么?”。于是,该回答可能含糊不清了。显然,我们走上了一条困难重重之路。
  2. 第二种可能性是增加足够的检验和比特,使发送方不仅可以检测差错,还可恢复差错。对于会产生差错但不丢失分组的信道,这就可以直接解决问题。
  3. 第三种方法是,当发送方收到含糊不清的ACK或NAK分组时,只需重传当前数据分组即可。然而,这种方法在发送方到接收方的信道中引入了冗余分组(duplicate packet)。冗余分组的根本困难在于接收方不知道它上次所发送的ACK或NAK是否被发送方正确地收到。因此它无法事先知道接收到的分组是新的还是一次重传!

        解决这个新问题的一个简单方法(几乎所有现有的数据传输协议中,包括TCP,都采用了这种方法)是在数据分组中添加一新字段,让发送方对其数据分组编号,即将发送数据分组的序号(sequence number)放在该字段。于是,接收方只需要检查序号即可确定收到的分组是否一次重传。对于停等协议这种简单情况,1比特序号就足够了,因为它可让接收方知道发送方是否正在重传前一个发送分组(接收到的分组序号与最近收到的分组序号相同),或是一个新分组(序号变化了,用模2运算“前向”移动)。因为目前我们假定信道不丢分组,ACK和NAK分组本身不需要指明它们要确认的分组序号。发送方知道所接收到的ACK和NAK分组(无论是否是含糊不清的)是为响应其最近发送的数据分组而生成的。

rdt 2.1 发送方
 rdt 2.1 发送方

rdt 2.1 接收方
rdt 2.1 接收方

        上面两图给出了对rdt 2.1的FSM描述,这是rdt 2.0的修订版。rdt 2.1的发送方和接收方FSM的状态数都是以前的两倍。这是因为协议状态此时必须反映出目前(由发送方)正发送的分组或(在接收方)希望接收的分组的序号是0还是1。值得注意的是,发送或期望接收0号分组的状态中的动作与发送或期望接收1号分组的状态中的动作是相似的 ;唯一不同的是序号处理的方法不同

        协议rdt 2.1 使用了从接收方到发送方的肯定确认和否定确认。当接收到失序的分组时,接收方对所接收的分组发送一个肯定确认。如果收到受损的分组,则接收方将发送一个否定确认。如果不发送NAK,而是对上次正确接收的分组发送一个ACK,我们也能实现与NAK一样的效果。发送方接收到对同一个分组的两个ACK(即接收冗余ACK(duplicate ACK))后,就知道接收方没有正确接收到跟在被确认两次的分组后面的分组rdt 2.2是在有比特差错信道上实现的一个无NAK的可靠数据传输协议,如下图所示。rdt 2.1和rdt 2.2之间的细微变化在于,接收方此时必须包括由一个ACK报文所确认的分组序号这可以通过在接收方FSM中,在make_pkt()中包括参数ACK0或ACK1来实现),发送方此时必须检查接收到的ACK报文中被确认的分组序号(这可通过在发送方FSM中,在isACK()中包括参数0或1来实现)。

rdt 2.2 发送方
rdt 2.2 发送方

rdt 2.2 接收方
rdt 2.2 接收方

3.经具有比特差错的丢包信道的可靠数据传输:rdt 3.0

        现在假定除了比特受损外,底层信道还会丢包,这在今天的计算机网络(包括因特网)中并不罕见。协议现在必须处理另外两个关注的问题: 怎样检测丢包以及发生丢包后该做些什么。在rdt 2.2中已经研发的技术,如使用检验和、序号、ACK分组和重传等,使我们能给出后一个问题的答案。为解决第一个关注的问题,还需增加一种新的协议机制。

        有很多可能的方法用于解决丢包问题(在本章结尾的习题中研究了几种其他方法)。这里,我们让发送方负责检测和恢复丢包工作。假定发送方传输一个数据分组,该分组或者接收方对该分组的ACK发生了丢失。在这两种情况下,发送方都收不到应当到来的接收方的响应。如果发送方愿意等待足够长的时间以便确定分组已丢失,则它只需重传该数据分组即可。你应该相信该协议确实有效。

        但是发送方需要等待多久才能确定已丢失了某些东西呢?很明显发送方至少需要等待这样长的时间:即发送方与接收方之间的一个往返时延(可能会包括在中间路由器的缓冲时延)加上接收方处理一个分组所需的时间。在很多网络中,最坏情况下的最大时延是很难估算的,确定的因素非常少。此外,理想的协议应尽可能快地从丢包中恢复出来:等待一个最坏情况的时延可能意味着要等待一段较长的时间,直到启动差错恢复为止。因此实践中采取的方法是发送方明智地选择一个时间值,以判定可能发生了丢包(尽管不能确保)。如果在这个时间内没有收到ACK,则重传该分组。注意到如果一个分组经历了一个特别大的时延,发送方可能会重传该分组,即使该数据分组及其ACK都没有丢失。这就在发送方到接收方的信道中引入了冗余数据分组(duplicaledatapacke)的可能性。幸运的是,rdt 2.2协议已经有足够的功能(即序号)来处理余分组情况。

        从发送方的观点来看,重传是一种万能灵药。发送方不知道是一个数据分组丢失,还是一个ACK丢失,或者只是该分组或ACK过度时。在所有这些情况下,动作是同样的:重传。为了实现基于时间的重传机制,需要一个倒计数定时器(countdowntimer),在一个给定的时间量过期后,可中断发送方。因此,发送方需要能做到:①每次发送一个分组(包括第一次分组和重传分组)时,便启动一个定时器。②响应定时器中断(采取适当的动作)。③终止定时器。

rdt 3.0 发送方
rdt 3.0 发送方

       

        上图 给出了rdt 3.0的发送方FSM,这是一个在可能出错和丢包的信道上可靠传输数据的协议;在课后习题中,将请你提供rdt 3.0的接收方FSM。下图 显示了在没有丢包和延迟分组情况下协议运作的情况,以及它是如何处理数据分组丢失的。在下图 中时间从图的顶部朝底部移动;注意到一个分组的接收时间必定迟于一个分组的发送时间这是因为发送时延与传播时延之故。在下图b~d中,发送方括号部分表明了定时器的设置时刻以及随后的超时。我会在后面的文章探讨了该协议几个更细微的方面。因为分组序号在0和1之间交替,因此rdt 3.0有时被称为比特交替协议(altemaling-bitprolocol)。

rdt3.0的运行,比特交替协议
rdt3.0的运行,比特交替协议

        

        现在我们归纳一下数据传输协议的要点。在检验和、序号、定时器、肯定和否定确认分组这些技术中,每种机制都在协议的运行中起到了必不可少的作用。至此,我们得到了一个可靠数据传输协议!

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值