RDT 协议 (可靠数据传输协议)

article/2025/10/9 9:50:34

RDT (reliable data transfer)协议详解

 

零、文档目录

  1. .名词解释

  2. 背景介绍

  3. rdt协议的实现

  4. 总结

  5. 疑问解析

  6. 参考文献

一、名词解释

        rdt协议(reliable data transfer)可靠数据传输协议

二、背景介绍

        计算机网络通过对网络进行分层设计,将一个庞大而复杂的系统,模块化层次化,( 大致分层如图 2.1所示 ) 其中的每个层次为其上层提供特定的服务内容, 并使用来自下层的特定功能, 各个层次中明确了其需要实现的内容, 但并不指明其中具体的实现方式。

                                                        2.1 (五层因特网协议栈)

        运行在应用层中的客户端(服务端)应用程序进程通过套接字将数据推送到运输层。同样地, 有服务端(客户端)进程通过套接字接受来自运输层的数据。对应用层而言, 它所能看到的底层就是一条可靠的信道(如图 2.2 所示)。但是,对于现实中的数据传输,由于受到噪声干扰、网络拥堵等各种影响,难免会出现数据受损、丢包等事故, 而rdt协议就是为了解决这样一个问题,而诞生的。

                                                        2.2 (应用层数据传输简图)

三、rdt协议的实现

        参考《计算机网络自顶向下》这本书,在这里我们从简单到复杂来探讨这个协议的实现过程(要注意的是, 我们在此处探讨的rdt协议是建立在(stop-and-wait)停等协议上的)

        首先, 先将各个部分做好定义和命名初始化处理, 为进一步探讨协议做好准备。

        我们将数据的发送方设定为 sender, 接收方设定为 receptor,发送方和接收方各自维护一个自己FSM(Finite-State-Machine)有限状态机, 用于记录当前的状态。我们用状态来描述发送方和接收方在执行通讯各个时期的特征。

1. rdt1.0

        在rdt1.0中我们只专注于考虑如何实现核心功能,而不去考虑其他异常。因此我们在此处假定两个应用层之间存在着这么一条可靠信道,它可以保证从应用层的一侧到另一侧数据不丢失,因此此时的发送方和接收方只会有一个状态。

发送方: 等待应用程序下发调用指令, 发送数据

接收方: 等待来自下层的调用指令, 接受数据并缓存

数据流动图如3.1 所示

                                                        (3.1 rdt1.0 数据流动图)        

数据流动情况分析

sender

  1. 应用进程调用 rdt_send(data)方法, 将数据推送至运输层
  2. 运输层调用 make_pkt方法, 将源自于应用程序的报文分组打包成报文段
  3. 运输层调用udt_send方法, 将报文段推送至信道

receptor        

  1. 较低层(比运输层低的层次)执行 ret_rev方法,将数据推送到运输层
  2. 运输层调用 extract, 从报文段中提取出数据(可能涉及分组等细节实现, 此处不作探讨)
  3. 运输层调用 deliver_data方法将数据推送至应用层

        此时, 我们就可以简单地实现让数据从sender端传输到receptor端了, 当然此时距离可靠数据传输还有一定的距离。因此, 在rdt2.0及以后的版本我们开始考虑当异常事件发生的时候, 如何保证数据的可靠性

2. rdt2.0

        在rdt 2.0 首先考虑比特差错出现的情况, 比特差错通常会出现在可能受损的物理部件之中, 因此需要引入比特差错矫正的功能。(udp的比特差错校验方法) 在考虑出现比特差错事件发生的 rdt 2.0 中,需要加入 肯定确认(ACK positive acknowledgement)、 否定确认(NAK negative acknowledgement)的情况。 对于否定确认的报文, 需要提示发送方重新发送该数据(数据恢复)。基于这种重传机制的可靠数据传输协议称为 自动重传协议(Automatic Repeat reQuest,ARQ)

于是 Sender 方需要增加一个状态,等待 ACK 或 NAK, 整个rdt 2.0 执行流程如图 3.2 所示

                                                                (3.2 rdt2.0 数据流动图)

数据流动情况分析

Sender 端

  1. 应用层调用rdt_send方法, 将数据推送至应用层
  2. 应用层调用make_pdt将数据打包成报文段, 并在报文段中封装进一个 校验码
  3. 应用层调用udt_send方法将打包完成的报文段推送至信道
  4. Sender端 此时状态迁移为 等待ACK应答 或者 NAK 应答状态

Receptor 端

  1. 较低层通过rdt_rcv方法, 将数据推送到运输层
  2. 运输层接收到报文段, 对报文段数据进行校验处理, 校验成功则执行第4步, 校验失败则跳转到第3步
  3. 发送NAK指令, 继续等待较低层的调用
  4. 发送ACK指令, 继续等待较低层的调用

Sender端

  1. 接收到NAK应答指令执行第2步, 接收到ACK执行第3步
  2. 接收到NAK,Sender直接将打包好的数据再一次通过udt_send方法推送到信道, 保持等待ACK或NAK指令状态
  3. 接受到ACK, Sender端不再阻塞, 可以发送新的数据, 状态迁移为等待上层调用状态

        需要注意的是: 由于在这里讨论的rdt协议采用了停等协议。因此, Sender端在等待ACK 和 NAK 答复指令的时候, 处在阻塞的状态。

3. rdt 2.1

        在rdt 2.0 阶段看起来已经解决了比特受损问题, 但实际上此时的协议仍是有着巨大缺陷的。

        由于数据流动的双向性, 在rdt2.0阶段, 我们无法保证Receptor端发送的答复指令是否发生比特差错情况, 因此很有可能Sender端收到了一个比特受损的应答指令, 为了解决Sender端收到比特差错的异常指令情况, rdt2.1版本在Sender端对数据报进行了编号处理*由于我们此处讨论的 rdt协议是运行在停等协议上的, 因此序列号设定可以以类似于链表一样的形式进行构建,由 previout->current 两个状态交替构成, 即 0 1 0 1 0 1,分别代表上一次以及当前处理的数据)当Sender端校验到来自receptor发送答复指令出现比特差错的时候,Sender端直接重发上次打包的数据。 相较于 rdt 2.0版本, 在receptor端增添了一个冗余分组(duplicate packet)处理, 即维护一个缓存,用于存储当前获取到的数据, 倘若第二次收到的数据为冗余数据(和上次接受到的数据相同),这就表明receptor端发送的回复指令出现了比特差错异常, 因此它可以直接丢弃掉本次收到的数据, 然后再发送一条对缓存数据的ACK确认指令。 而对于非冗余数据, receptor端则是将新数据置换到缓存区中, 随后发送一个对本次数据的ACK确认指令。

rdt 2.1为什么不效仿 rdt 2.0中, 让receptor端去接受一个 ack或 nak, 这是因为可能出现一个比较有趣的问题, 这个问题后续讨论

数据流动如图3.3所示

                                                        (3.3 rdt2.1 数据流动图)

数据流动情况分析

Sender 端

  1. 应用层调用rdt_send方法, 将数据推送至应用层
  2. 应用层调用make_pdt将数据打包成报文段, 并在报文段中封装进一个 校验码和一个值为 0 或 1的序号
  3. 应用层调用udt_send方法将打包完成的报文段推送至信道
  4. Sender端 此时状态迁移为 等待序号为 0 或 1 的报文段 ACK应答 或 NAK 应答状态

Receptor 端

  1. 较低层通过rdt_rcv方法, 将数据推送到运输层
  2. 运输层接收到报文段, 对报文段数据进行校验处理, 校验成功则执行第4步, 校验失败则执行第3步
  3. 发送NAK指令,继续等待下层调用
  4. 检测数据序号, 如果是冗余数据, 直接丢弃数据,发送对缓存栈中数据的ACK指令,对于非冗余数据, 则将数据置换到缓存栈之中, 发送一个确认对本次数据的ACK指令, 继续等待来自下层的调用

Sender端

  1. 1. 接收到应答指令后,进行数据校验处理, 如果数据校验错误, 直接重传上次数据, 如果数据校验正确,则执行第 2步
  2. 2. 判断接受到的应答指令,如果指令为ACK执行第3步, 如果指令为 NAK 执行第4步
  3. 3. 接收到ACK指令, Sender端不再阻塞, 可以发送新的数据 1 或 0, 状态迁移到 等待来自上层调用
  4. 4. 接收到NAK指令, 重传上次数据, 状态迁移到 等待ACK或NAK状态

rdt 2.2

        实际上rdt 2.2 并没有做出更多变更, 它只是在rdt2.1基础上进行了一次逻辑优化, 因为有了序号的存在,receptor端不在需要用NAK指令去表示收到的数据产生了比特错误。 取而代之是, 对于比特受损的数据, receptor端直接丢弃, 并发送一个对缓存区数据的确认ACK(一开始缓存区为空也不要紧,由于序列是010101交替的序列,只要发送一个与当前ACK不同的序号即可),而此时, Sender端也需要维护一个缓存, 用于记录上一次发送的数据, 当接受到的ACK与缓存序列号相同, 那么就表示发送的数据发生了比特差错, 此时重新发送一次缓存区中的数据即可。

数据流动如图 3.4所示

                                                                (3.4 rdt2.2 数据流动图)

数据流动情况分析

Sender 端

  1. 应用层调用rdt_send方法, 将数据推送至应用层
  2. 应用层调用make_pdt将数据打包成报文段, 并在报文段中封装进一个 校验码, 和一个值为0 或 1的序号 , 并将其存储至缓存区
  3. 应用层调用udt_send方法将打包完成的报文段推送至信道
  4. Sender端 此时状态迁移为 等待序号为 0 或 1 的报文段 的ACK或NAK应答状态

Repetor 端

  1. 较低层通过rdt_rcv方法, 将数据推送到运输层
  2. 运输层接收到报文段, 对报文段数据进行校验处理, 校验成功则执行第4步, 校验失败则执行第3步
  3. 发送缓存区数据序号的确认ACK指令,保持等待下层调用的状态
  4. 检测本次数据序号, 如果是冗余数据, 直接丢弃数据,发送缓存栈中数据序号的ACK指令,对于非冗余数据, 将数据置换到缓存区之中,并发送一个对本次数据序号的确认ACK指令

Sender端

  1. 接收到应答指令后进行数据校验处理, 如果数据校验错误, 直接重新发送上次数据, 如果正确则执行第 2 步
  2. 判断接受到的应答指令,如果指令为ACK中的序号等于缓存区的序号,执行第 3 步, 如果ACK指令序号不等于缓存区序号则执行 第4 步
  3. 重新发送上次数据, 状态迁移到 等待ACK应答指令
  4. Sender端不再阻塞, 可以发送新的序号为 1 或者 0 的数据, 状态迁移到 等待来自上层调用

rdt 3.0

        在处理好了比特差错的问题之后, 需要考虑的就是来自底层信道传输的另一个问题, 丢包异常( 即发送方或者接受方由于网络阻塞等状况,并没有收到来自于对方的应答数据, 在现实中丢包现象是非常常见的), 因此, 我们可以加入一个定时器来处理丢包现象, 当发送一个报文段的时候, 就开启一个定时器, 在定时器结束期间, 如果没有收到对应数据的应答报文, 则重传数据。

数据流动分析

Sender 端

  1. 应用层调用rdt_send方法, 将数据推送至应用层
  2. 应用层调用make_pdt将数据打包成报文段, 并在报文段中封装进一个 校验码, 和一个值为0 或 1的序号 , 并将其存储至缓存区
  3. 应用层调用udt_send方法将打包完成的报文段推送至信道, 并启动一个定时器事件
  4. Sender端 此时状态迁移为 等待序号为 0 或 1 报文段 的ACK应答状态
  5.  倘若在定时器等待时间内, 没有收到响应, 则重新执行第3步

Receptor端

  1. 较低层通过rdt_rcv方法, 将数据推送到运输层
  2. 运输层接收到报文段, 对报文段数据进行校验处理, 校验成功则执行第 4 步, 校验失败则执行第 3 步
  3. 发送缓存区数据序号的确认ACK指令, 同时开启一个定时器, 保持等待下层调用的状态
  4. 检测数据序号, 如果是冗余数据, 直接丢弃数据,发送缓存区中数据序号的ACK指令,对于非冗余数据, 将数据置换到缓存区中, 发送一个对该数据序号的确认ACK指令, 同时开启一个定时器
  5. 倘若在定时器等待时间内, 没有收到响应, 则重新执行第3或第4步

Sender端

  1. 接收到应答指令后进行数据校验处理, 如果数据校验错误, 直接重新发送上次数据, 如果正确则执行步第 2 步
  2. 判断接受到的应答指令,如果指令为ACK中的序号等于缓存区的序号,执行第 3 步, 如果ACK指令序号不等于缓存区序号则执行 4
  3. 重新发送上次数据, 状态迁移到 等待ACK, 同时开启一个定时器
  4. Sender端不再阻塞, 可以发送新的序号值为 1 或 0 的数据, 状态迁移到 等待来自上层调用
  5. 倘若在定时器等待时间内, 没有收到响应, 则重新执行第 3或 第4步

四、总结

        至此,在rdt3.0我们已经得到了一个可靠的数据传输协议,当然它只是一个抽象的雏形, 建立于停等协议之上, 还需要不少细致的优化, 让其更好的切合现实, 比如如何脱离停等协议实现更高的传输率, 以及拥塞控制等等。文章内的方法为了保证准确性, 表达式大多参照于《计算机网络自顶向下方法》 书籍中的内容, 但是为了简化一下表达, 也做出了一点变更。

五、疑问解析

1.如何确认数据发生比特受损现象

参照UDP协议中的检验和校验方式,在这里举一个简单的例子(UDP中的校验方式, udp通过校验和的方式来实现差错检验功能

        例如, 发送了两个16bit的报文:

                  0101 0101 0101 1111  

                  1111 1111 0000 1111

   求和有 1 0101 0100 0000 1110

       回卷    0101 0100 0000 1111 (回卷即把溢出部分的数据重新进行逻辑加运算到序列尾部)

         取反 1010 1011 1111 0000

        在发送时数据中会添加如下一个字段, 其值为经过上述运算后的一串序列

        检验和:1010 1011 1111 0000

        当接收方, 收到来自底层的数据时, 会开始进行检验, 首先将应用数据中所有数据行进行求和运算得到一个和序列,将和序列与检验和做一次逻辑加运输, 得到的预期结果应该为 1111 1111 1111 1111,倘若不是,则表示本次数据发生了比特差错异常。

2.为什么rdt2.1 不采用 rdt2.0的方法, 让发送端给接收端发送ACK和NAK信息呢?

我们可以考虑如下这么一个例子:

        Sender端发送了一个报文段给Receptor端, 于是Receptor端回复了一个ACK给Sender, 但不幸的是 Sender端得到的ACK比特受损, 于是 Sender端发送了NAK, 此刻Receptor端得到了NAK, 又发送了一个ACK, Sender端口得到了这个ACK。此时的Sender端无法判断这个ACK是对于第一次数据发送成功的应答ACK还是来自自己NAK指令的应答ACK, 这使得指令数据具有了二义性, 这是一种不好的设计形式。

        不止是以上这种特殊情况, 由于丢包和比特受损情况, 我们有时不得不传输许多不携带具体内容的ACK/NAK数据, 这是一种对数据的额外开销,也容易造成信道阻塞。

六、参考文献

1.《计算机网络自顶向下方法》

2.《图解TCP/IP》


http://chatgpt.dhexx.cn/article/1cmKBQOK.shtml

相关文章

rdt 可靠数据传输协议

计算机网络的设计基本方案是复杂化,多功能化应用层,运输层的协议设计,从而使得网络层,链路层,物理层变得相对简单,网络搭建的物质条件变得简单。由于网络层较为简单,采用了无连接的协议&#xf…

前端开发学习之一------前端开发是什么以及我们要学什么

1.web前端开发工程师是做什么的 简单地说,就是要与网站打交道 2.成为一名web前端工程师需要具备的条件 ①兴趣 ②敲代码(实践、需要去练习) 3.Web前端开发工程师需要学习什么(重点:HTML,CSS,JavaScript硬性指标) ①软件(代码的辅助工具) 浏览器:浏览器有非常多,(…

前端学习.

前端学习 基础学习路线网页简介1.html2.网页 常用的浏览器Web标准HTML标签(上)HTML语法规范HTML基本结构标签网页开发工具HTML常用标签HTML中的注释和特殊字符 HTML标签(下)表格标签表格总结 列表标签列表总结 表单标签综合案例直…

我的前端学习经历

我最近在开发一个NFT相关的Saas,部分截图如下: 这是我一段时间前,朋友圈发的图,现在Saas在页面上有点变化,但懒得再截图了。客观而言,布局还可以,这一套的技术栈是:React TailwindC…

前端学习路线

这里写目录标题 1、产品经理。2、UI设计师。3、项目经理。4、最终用户。 一、基础二、JS1.JS变量2.JS运算符3.JS数组4.JS流程语句5.JS字符串函数6.JS函数基础7.JS基础DOM操作8.JS正则表达式9.JS数据类型 三、后端语言四、学习方法建议 前端开发工程师 不仅要掌握基本的Web前端开…

WEB前端开发学习5大网站,你用过几个?

“工欲善其事,必先利其器”,学习WEB前端开发也是一样。 一、前端视频教程-51自学网 我要自学网是由佛山市丰智胜教育咨询服务有限公司倾力打造的在线实用技能学习平台。该平台成立于2007年6月7日,是一家专业从事软件视频教程开发的教育服务机构。开发团队由奋战在教学第一线…

前端开发工程师学习路线图(收藏版)

在网上看到很多类似“前端现在是不是饱和了,是不是不好找工作了呀?”这类问题,就这类问题也和小伙伴进行了探讨,大家一致认为——不是前端饱和了,而是现在前端的工作在不断独立,门槛越来越高,再…

什么是前端开发及学习路线

一、什么是前端开发 前端开发是创建Web页面或app等前端界面呈现给用户的过程,在这个过程中需要学习并使用,HTML、CSS、JavaScript以及衍生出的各种技术、框架;其中最基础也最核心的就是:HTML、CSS、JavaScript,俗称“…

前端开发学习及工具网站(持续更新)

前端开发学习及工具网站 该文章主要是记录前端开发中好的学习网站或者工具网站 大部分实用网站来源抖音鱼皮大佬分享,这里分享给大家 1、w3cschool(编程狮) 这个网站适合0基础学前端的同学,内容简单易懂,在闯关中进行学习,能够刺…

前端开发免费学习资源分享

知乎上很多同学在问什么前端培训,怎么入行啥的 我这里给大家先总结一下,老师会给大家分享一些基础的学习资料如果你入不了门,就不要去搞啥前端了, 没有用的,一点基础没有去培训你也听不懂 黑马程序员pink老师前端入…

送给大家一套完整的web前端开发学习路线

本文来源:千锋web前端开发 近几年IT业可谓是发展火热,而且新生了很多的职业。在这众多的新生职业中备受瞩目的当属web前端工程师了,web前端在IT行业真正受到重视的时间不超过五年,但是web前端的发展前景却是非常的可观&#xff0…

Web前端开发学习(一)

目录 一、HTML的基础Tag用法 以下内容使用VSCode编写,LiveServe插件和Chrome浏览器生成网页。 Web前端学习,只要学会HTML和CSS(层叠样式表)就可以搭建出自己的页面啦!其中HTML的功能是为页面添加内容,CSS…

Web前端学习

第一步:拨云见日 1.基础部分:HTML 、CSS 2. 切图流程:传统切图、智能切图、公司流行切图 3.实战阶段:PC企业站布局 PC游戏站布局 第二步:溯本求源 1.扩展: HTML 、CSS 2 .新语法: HTML5 、 C…

Web前端入门学习

目录 导言1.拨云见日2.溯本求源3.风生水起4.巧夺天工 Web的入门知识1.什么是HTML、CSS?2.VS code 编辑器?3.学习编辑器的基本使用4.chrome浏览器?5.了解网站开发?6.HTML基础知识与属性7.HTML的初始代码8.HTML注释?9.HT…

关于前端的学习

最近在网上想模拟一个ai的围棋,然后在gitee上找了一个算法,想要启动一下。 https://gitee.com/changjiuxiong/myGoChess?_fromgitee_search 使用说明是这样的: 使用说明 npm install npm run dev 打开index.html 可自定义棋盘大小: new Game…

前端开发学习常用网站网址及介绍(都是免费的)

在开发的时候,想记住所有的单词基本是不可能的,所以就需要进入文档,只要理清需求能做出来,就很不差了!! 扫码加博主微信 1.百度,俗称度娘,有不懂的就问百度,有问必答&am…

前端开发需要学习什么?掌握哪些技术?

前端开发需要学习什么?随着计算机行业的不断发展,无论是在企业还是个人中,web前端技术都得到广泛的使用。web前端开发师是一个非常新兴的职业,在计算机行业中,web前端得到很大的重视。那么在学习web前端开发需要学习什…

自学Web前端开发学习讲解 – 入门篇

很多人都对web前端感兴趣,这一期主要聊关于如何入门学习Web前端开发的过程分享,此篇适合想入门初学者,大佬就不用看了。主要内容是以本人这一路自学web前端的一些经验和建议,学习哪些知识,以及如何正确的去学&#xff…

前端开发需要学习什么?

前端开发需要学习什么?web前端相对于编程语言Java、C等来说相对要更容易入门,更适合新手学习。所以有越来越多的人想要学习web前端开发,那么我们学习web前端开发需要学习什么呢? web前端都要学习哪些内容呢? 1、HTML5CSS3&#…

适合普通大学生的前端开发学习路线

大家好,我是帅地。 假如你没有明确的目标,或许可以按照我说的学习路线来学习一波,我写的每一份学习路线,不会很全面,因为我认为,东西列的太多,反而不利于新手的学习,所以我列举的&a…