概述
我们都知道TCP协议是一种可靠的运输层协议,它可以保证HTTP报文无差错、无损失且有序地从客户端到达服务器。那么这种可靠性是怎样实现的呢?这便是本文要讨论的重点
- 可靠数据传输(rdt)为其上层提供这样一种服务——数据可以通过一条可靠的信道进行传输,借助于可靠信道,传输数据比特就不会受到损坏或丢失,而且所有数据都是按照其发送顺序进行交付。如下图所示
- 可靠数据传输协议
我们知道IP协议是不可靠的,因此需要我们在不可靠的IP协议上使用一种可靠数据传输协议来实现数据的可靠传输(如TCP协议),而TCP采取的许多原理正是我们下面要提到的rdt协议
rdt1.0
- 假设:为了更好的理解,首先假设底层信道完全可靠(不像IP协议那样不可靠),即底层信道既不会发生比特差错(0变1,1变0)又不会发生分组丢失,并且同时假设接收端的接受速率和发送端的发送速率一样快,没必要通知发送端控制发送速率。
- 以上面的假设为前提,在发送方向接收方发送数据时,接收方不必要向发送方反馈任何消息,因为发送方能100%确保数据可以正确无误地发送到接收方,并且接收方没必要通知发送方控制发送速率
我们通过rdt1.0协议的FSM(有限状态图)来看一下rdt1.0的工作机理
rdt2
rdt1.0是完全理想状态的,实际过程中肯定会发生比特差错。我们先保留分组不会丢失这个假设,引入比特差错(rdt2.0、2.1、2.2都是这个假设)。
那么我们怎么处理存在比特差错的情况呢?看一个实例
- 假如老师在向学生授课,一节课很长,老师每讲一部分就会向学生询问是否理解,如果学生理解(肯定确认(ACK)),则继续讲课;如果学生不理解(否定确认(NAK)),则重新讲没听懂的那部分,这样可以确保每一部分都被学生吸收。
- 重讲的过程类似于发送端向接收端重新发送出现比特差错的分组的过程。在网络中,基于这种重传机制的可靠数据传输协议称为自动重传请求协议------ARQ
- 只要老师没有收到学生的肯定确认(ACK),老师就不会继续往下讲新的内容。也就是说发送端在没有确信接收端已正确接收当前分组,发送端是不会发送新的数据的,有这种行为的协议被称为停等协议
rdt2.0、2.1、2.2都是采用了一个类似老师讲课这样思路来处理比特差错的
rdt2.0
先看一下rdt2.0的FSM 从图中可以看出当发送端处于右边状态时,不会从上层获取更多的数据,也不会发送新的数据,因此rdt2.0是停等协议,并且当发送端收到否定确认时会重新发送该分组,因此rdt2.0是ARQ协议
rdt2.1
- 在不考虑分组丢失的情况下rdt2.0看似已经近乎完美了,但是其实它有一个致命的缺陷就是如果ACK或NAK分组发生了比特差错,rdt2.0是没有相应的处理措施的,于是我们引入了rdt2.1。
- 在rdt2.1中,针对ACK或NAK分组发生比特差错的情况,如果发送方收到了含糊不清的ACK或NAK分组(发生比特差错)时,只需要重传当前分组既可。然而这种方法会产生一个问题,就是接收方不知道发送方是否正确地收到了ACK或NAK分组,因此接收方无法事先确认它收到的是新的分组还是一次重传。解决这个问题的简单办法就是让发送方对其数据分组编号,并在分组中添加一个序号字段。这样接收方就可以根据分组序号来判断收到的是新的分组还是一次重传。
- 对于rdt2.1这种停等协议可以在分组中使用1bit的开销来存储序号字段(序号只能为0或1),例如010101…(这个序列一直都在发送新的分组,没有重传),而010110(发送方发送的第五个分组是一次重传)。ACK或NAK分组自身是不需要序号的
- 来看一下rdt2.1的FSM
- 关于接收端图中紫色部分追加一个说明,就是如果在左边状态下依然收到了序号为1的分组,必然是因为在从右边向左边状态转移时向发送方发送的ACK分组出现了比特差错,或者从右边向左边状态转移后紧接着多次连续执行红色箭头指向的动作时向发送方发送的ACK分组出现了比特差错,一旦发送方正确接收到ACK分组,那么发送方不会再向接收方发送序号为1的分组,只会发送序号为0的分组。
rdt2.2
- 为了更加简明,我们不使用NAK分组,通过给ACK分组加上序号来实现与rdt2.1相同的效果。发送方连续接收到对同一个分组的两个 ACK 后,就知道接收方没有正确接收到跟在被确认两次的分组后面的分组
- 关于接收端红色箭头部分追加一个说明,当状态从右边迁移过来时,接收方就已经正确接收了一个序号为1的分组,如果在状态从右边迁移过来的过程中向发送方发送的序号为1的ACK分组出现了差错(序号变为0或者其他位出现了错误),发送端会重新发送序号为1的分组,知道发送方收到一个正确的并且序号为1的分组,这之后发送方只会向接收方发送序号为0的分组,如果该分组发生了比特差错,接收方执行红色箭头指向的动作,向发送方发送一个序号为1的ACK分组,这样发送方会连续接收两个或两个以上的序号为1的ACK分组,发送方此时处于右上角的状态,便会向接收方重传序号为0的分组。
rdt3.0
- rdt2.0、2.1、2.2都是假设分组不会丢失,在了解了rdt2的基础上我们回归到符合实际的情况下,即既会产生比特差错,又会产生分组丢失
- 针对分组丢失,rdt3.0通过这样一种机制来处理:发送方发送一个分组时启动一个倒计数定时器,如果在倒计数定时器倒计时结束之前收到了ACK响应,则中断定时器,进入准备接收来自上层的下一次调用。如果倒计数定时器超时,则发送方认为分组丢失,向接收方重传该分组,并且重新启动定时器
- 需要注意的是
①定时器超时有以下三种可能:数据分组确实丢失、ACK丢失、过度时延(发送方与接收方之间的一个往返时延大于倒计数定时器) ②重传在发送方到接收方的信道中引入了冗余数据分组,但是rdt3.0是基于rdt2.2的,rdt2.2可以处理冗余数据分组,因此rdt3.0也可以处理冗余数据分组 - 关于发送端绿色箭头处的Λ,在rdt2.2中,这里是要重传数据分组的,但是这里没有,是因为即使这里不重传数据分组,等到timeout(倒计数定时器超时)时,也会重传数据分组。
- 那么为什么不将发送端绿色箭头和红色箭头处的状态转换合并呢?因为如果是因为ACK发生差错或者收到序号不正确的ACK分组而需要重传,不一定需要start_timer,而timeout一定要start_timer
流水线可靠数据传输协议
为什么使用流水线
通过上面对rdt协议的讨论,我们大致了解了可靠数据传输协议,但是rdt有一个很大的缺点就是,当发送方处于等待ACK或NAK分组的状态时无法接收来自上层的数据,也就是说由于rdt协议是停等协议,会导致发送方信道的利用率极低,因此我们需要通过流水线的方式来提高信道的利用率
- 流水线可靠数据传输协议 :不使用停等方式,允许发送方发送多个分组而无需确认等待,这样会大大提升发送方信道的利用率
流水线对可靠数据传输协议带来的影响
- 必须增加序号范围,每个分组(不包含重传的)必须有唯一的序号
我们知道一个分组的序号存储在分组首部的固定长度字段中,序号字段长度为kbit,则该序号范围是[0,2^k-1]. - 发送方和接收方也需要能够缓存多个分组
发送方:至少能够缓存那些已被发送但未被确认的分组 - 所需序号范围和缓存大小取决于协议是如何处理丢失、损坏及时延过大的分组,这里这类分组有两种方法:回退N步协议和选择重传协议
流水线协议中恢复差错的两种方法
回退N步协议(GBN协议、滑动窗口协议)
在GBN协议中,允许发送方发送多个分组而不需等待确认,但它也受限于在流水线中未确认的分组数不能超过某个最大允许数N
- 通过基于ACK、无NAK的GBN协议的FSM图来了解GBN的原理
选择重传协议(SR协议)
GBN协议虽然实现了流水线式传输数据,提高了发送方信道的利用率,但是GBN有一个很大的缺陷就是一旦超时,会有许多不必要重传的分组被重新传送。尤其是当窗口长度N很大时,随着差错率的提升,信道中会充斥着不必要重传的分组。
- SR协议让发送方仅重传那些它怀疑在接收方出错(丢失或受损)的分组从而避免不必要的重传
- SR协议原理:
发送方: 为每一个分组设置一个定时器,这样可以在某一个分组超时时对其单独进行重传 接收方: SR接收方将确认一个正确接收的分组而不管其是否按序。在未出现分组丢失之前,正确接收到的分组都会被交付给上层。一旦出现分组丢失,失序的分组将被接收方缓存起来,直到所有丢失分组(即序号更小的分组)皆被接收为止,这时将缓存中的分组一起交付给上层(实在不想再作图了)
|