TCP实现可靠传输的实现

news2024/12/23 20:51:31

TCP实现可靠传输的实现

目录

  • TCP实现可靠传输的实现
    • ARQ协议
      • 停止等待协议(古老)
      • 连续ARQ协议
        • 累计重传(回退N帧的ARQ协议)
        • 缓存确认(选择重传ARQ协议)
      • 超时重传的时间选择
    • TCP的流量控制
      • 零窗口探测报文段
      • Nagle算法
    • TCP的拥塞控制
      • TCP的拥塞控制方法
      • 路由器主动队列管理AQM
    • 参考

ARQ协议

为了方便表示我们在本小节中将A叫做发送方,而B叫做接收方

停止等待协议(古老)

停止等待就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。这其实就有点类似与半双工了。

停止等待协议的工作原理可以通过下图了解。

IMG_20230213_185732

理解停止等待协议只要根据上图看图说话就行。在无错误状态下A发送消息后在收到B返回的确认消息后再发出下一条消息。上图中的(b)则说明了若出现发送方报文出错重传的机制。下图展现了另外两种可能出现重传的情况。

IMG_20230213_185740

有一些细节需要注意:

  • A在发送完一个分组后,必须暂时保留已发送的分组的副本
  • 分组和确认分组都必须进行编号。这样才能明确时哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认。比如出现已失效的连接请求报文段
  • 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。需要考虑到网络中出现的时延和拥塞问题。

停止等待协议的优点是比较简单,但是信道利用率低

IMG_20230213_185748

根据上图我们,此时信道的利用率U可以粗略地通过下式来计算:
U = T D T D + R T T + T A U = \frac{T_D}{T_D + RTT + T_A} U=TD+RTT+TATD

连续ARQ协议

通过前面的介绍,我们可以知道停止等待协议的传输效率太低。我们可以想到用下图这种流水线的传输方式,显然这样可以提高信道的利用率。但是这也会带来新的问题,可以可以通过滑动窗口协议搭配不同的确认方式来解决

IMG_20230213_185805

累计重传(回退N帧的ARQ协议)

IMG_20230213_193629

滑动窗口协议限定了一次性发送数据的条数,同时限定了如何发送下一组请求。我们搭配着上面这副图来理解累计重传的原理。

例如,发送方一次性发送了5个分组,但是第二个分组丢失了。这个 时候接收方只能对第一个分组进行确认。发送方无法确认后面四个分组中还有哪个是传到了的,于是只好将后后面的四个分组全部重传。这也就出现了上图中滑动窗口向右滑动一个序号的原因,这就叫做Go-back-N(回退N)。

采用累计确认的方式时,接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认

通过这种多个重传的案例,可以清楚地知道连续ARQ在通信线路质量不好时带来的负面影响。

缓存确认(选择重传ARQ协议)

IMG_20230213_195916

我看别的很多都称这种方式为选择重传,但感觉根据自己的理解这个叫做缓存确认更容易理解。通过上图我们可以看到,在接收方可发送方分别需要维护一个发送缓存和一个接收缓存。

同样的我们对照着下图,来理解缓存确认的运作原理。例如,A已经发送了34-41分组中的数据,但是其中37、38、40都没有按照顺序被B收到。对于这三个未按序到达的数据而言可能是提早到、晚到、没传到。我举以下两个例子:

① 37、38、40 都提前到了

在数据提前到的时候,这些数据会先被B存放在自己的接收缓存中。当收到了36号数据后37、38依次接上并分别发送确认报文。40则在收到39后再接入。(如果过程中出现超时,也会触发A的重传)

②37没传到 38、40都提前到了

这个时候接收方最高发送的确认报文是36。而37号报文由于超时,A重新发送37这部分的数据,同时滑动窗口也会往后面移动,并发送42、43、44这三个序号的数据。

这里其实每次A收到确认号落在发送窗口内(考虑到“已失效的连接请求报文段”),那么A就可以使滑动窗口继续向前移动。

IMG_20230213_193746

发送缓存用来暂时存放:

  1. 发送应用程序传送给发送方TCP准备发送的数据
  2. TCP已发出但尚未收到确认的数据

接收缓存用来暂时存放:

  1. 按序到达的、但尚未被接受应用程序读取的数据
  2. 未按序到达的数据

根据前面的了解,我们需要注意以下三点:

  1. 虽然A的发送窗口是根据B的接收窗口设置的,但再同一时刻,A的发送窗口并不总是和B的接收窗口一样大(可以小于接收窗口)。
  2. 对于不按序到达的数据如何处理,TCP标准并无明确规定。如果接收方将不按序到达的数据一律丢弃,这样对网络资源的利用不利。因此TCP通常对不按序到达的数据先临时存放再接收窗口中,等到字节流中缺少字节收到后,再按序交付上层的应用程序
  3. TCP要求接收方必须有累计确认的功能,这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送的时候把确认信息顺便捎带上。但TCP规定,确认的推迟时间不应超过0.5秒。

超时重传的时间选择

TCP采用了一种自适应算法,它记录了一个报文段发出的时间,以及收到相应的确认的时间(可以去看TCP尾部的选项字段)。这两个时间之差就是报文段的往返时间RTT。TCP保留了一个RTT的一个加权平均往返时间RTTs(也叫平滑的往返时间)。每当第一次测量到RTT样本值。但以后每测量到一个新的RTT样本,就按下式重新计算依次RTTs:
新的 R T T s = ( 1 − α ) × ( 旧的 R T T s ) + α × ( 新的 R T T 样本 ) 新的RTTs = (1 - \alpha) \times (旧的RTTs) + \alpha \times (新的RTT样本) 新的RTTs=(1α)×(旧的RTTs)+α×(新的RTT样本)
一般认为RTT样本值对新的RTTs的值影响较大,RFC 3298 推荐的 α \alpha α值为0.125。**超时重传时间 RTO(Retransmission Time-Out)**应略大于上面得到的平滑RTTs。RFC 6298推荐使用下式计算RTO:
R T O = R T T s + 4 × R T T D RTO = RTTs + 4 \times RTT_D RTO=RTTs+4×RTTD
R T T D RTT_D RTTD是RTT的偏差的加权平均值,它与RTTs和新的RTT样本之差有关。
新的 R T T D = ( 1 − β ) × ( 旧的 R T T D ) + β × ∣ R T T s − 新的 R T T 样本 ∣ 新的RTT_D = (1 - \beta) \times (旧的RTT_D) + \beta \times|RTTs - 新的RTT样本| 新的RTTD=(1β)×(旧的RTTD)+β×RTTs新的RTT样本
这里的 β \beta β是一个小于1的系数,它的推荐值是0.25.

通过上面的公式我们就可以计算出重传时间RTO。但是我们在此时要考虑到超时重传时出现时:**如何判定此报文段时对先发送的报文段的确认,还是对后来重传报文段的确认?**由于重传的报文段和原来的报文段完全一样,因源主机在收到确认后,就无法做出正确的判断,而正确的判断对确定平均RTTs 的值关系很大,影响关系可以通过下图看出。

IMG_20230213_214431_edit_1767143973110561

于是又了Karn算法:在计算加权平均RTTS时,只要报文段重传了,就不采用其往返时间样本。这样就得出了加权平均RTTS和RTO就较准确。

但是若出现:报文段的时延突然增大很多。若不考虑重传的报文段重传时间,继续按照原来的RTO。将会导致出现大量的重传。

于是有了改进,方法是:报文段每重传依次,就把超时重传时间RTO增大一些(经典的做法是2倍)。当不再发生报文段的重传时,才根据RTO的计算公式计算超时重传。

TCP的流量控制

所谓的流量控制就是让发送方的速率不要太快,要让接收方来得及接收。(注意:流量控制是一种接收方对发送方来讲的机制,是一个端到端的问题)

利用滑动窗口机制可以比较方便地在TCP连接上实现对发送方的流量控制。

现在我们假定数据流向是单向的,也就是说发送方A只负责发送数据,不负责处理和接受数据,接收方B只负责处理和接收数据,并且对接收到的数据进行应答(ACK)。

在A和B建立连接的时候,B将自己的接收窗口RWND(receiver window)设置为400字节。这时候A将自己的发送窗口也设置为400,如下图所示。A给B连续发送了3个TCP报文段,每个报文段都包含100字节的数据,其中第三个TCP报文段因某种网络原因丢失。同时A收到了来自B的应答报文段,B调整接收窗口rwnd = 300。此时发送窗口应该是在301-500.于是A就继续发送301-400,401-500这两段报文。这时也触发了A201-300这段报文的超时重传。随后收到了对401-500这段报文的确认(这个时候说明前五段报文都已经被B收到了),并设置rwnd = 100。于是A根据rwnd再次调节发送窗口为100字节,此时发送窗口移动到了501-600的位置。在收到501-600这段报文后,根据rwnd = 0将发送窗口设置为0。

此时A需要等待B发送的新的接收窗口大小(rwnd > 0)才能继续发送数据。于是B向A发送更新自己rwnd的报文,但是意外出现了,这个更新报文段丢失,此时将会导致A在等待B的rwnd,B在等待A的新数据,于是出现了死锁局面

IMG_20230214_094326_edit_7980999840968

零窗口探测报文段

为了防止这种意外的发生,我们设置A在收到B的0接收窗口大小(rwnd=0)时会自动启动一个“持续计时器”,当持续计时器timeout时,如果还没有收到来自B的rwnd更新报文段,则会发送一个零窗口探测报文段(携带1字节数据),当B接收到这个TCP报文段后,会给A回复一个rwnd的更新,如果此时rwnd > 0,那么A就可以继续发送数据,如果rwnd=0,则重新启动一个持续计时器,重复上述步骤。

这也出现了另外一个问题糊涂窗口综合征:当B对应的交互式应用进程每次仅仅接收缓存中的1字节数据(这样使接收缓存空间仅腾出1字节),如果这个时候刚好收到了零窗口探测报文段,就会将rwnd设置为1,这样发送方就只能发送来1个字节的数据.这样进行下去,使网络的效率很低。

解决这个问题的方案是:

接受方等待一段时间,使得接收缓存已有足够空间容纳一个最长报文段MSS,或者等到接收缓存已有一般空闲空间。只要出现两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。

Nagle算法

为理解Nagle算法 ,我们可以设想以下场景:TCP的发送应用进程把要发送的数据逐字节地送到TCP发送缓存。这个时候为了提高网络的吞吐量,Nagle算法规定:

若应用进程把要发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。Nagle算法还规定,当已到达发送缓存的数据已达到发送窗口的一半或已到达报文段的最大长度时,就立即发送一个报文段。

TCP的拥塞控制

在某段时间内,如果网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做拥塞。可以把出现网络拥塞的条件写成,如下式子:
∑ 对资源的需求 > 可用资源 \sum 对资源的需求 > 可用资源 对资源的需求>可用资源
拥塞控制就是防止过多的数据注入到网络中,这样可用使网络中的路由器或链路不至于过载。拥塞控制是一个全局性的过程

IMG_20230214_111105_edit_12417588050708

  • 提供的负载 代表单位时间内输入给网络的分组数目。
  • 吞吐量 代表单位时间内从网络输出的分组数目

TCP的拥塞控制方法

TCP进行拥塞控制的算法有四种:慢开始拥塞避免快重传快恢复

下面考虑的拥塞窗口是基于滑动窗口协议的。发送发维护了一个**拥塞窗口cwnd(congestion window)**的状态变量。同时认为发送方超时计时器启动时,就判断网络出现拥塞。因为传输出差错而丢失分组的可能性比较小。

IMG_20230214_111630_edit_12504478549653

慢开始算法

慢开始就是由小到达逐渐增大注入网络中的数据字节,或者说是从小到大逐渐增大拥塞窗口数值。(RFC5861规定初始的cwnd设置为不超过2至4个)。

慢开始规定,在每收到一个对新报文段的确认后,可用把拥塞窗口增加最多一个SMSS的数值。为了避免cwnd过大,还需要设置一个慢开始门限 ssthresh

  • 当cwnd < ssthresh时,使用慢开始算法
  • 当cwnd > ssthresh时,使用拥塞避免算法
  • 当cwnd = ssthresh时,既可以使用慢开始算法,也可使用拥塞避免算法。

拥塞避免算法

拥塞避免算法就是让cwnd缓慢增大。执行算法的过程大概是这样的:每经过一个往返时间RTT,发送方的拥塞窗口cwnd的大小就增加1。拥塞避免并非完全避免拥塞,而是让拥塞窗口增长得缓慢一些。

快重传算法

在发现有分组丢失,认为网络出现了拥塞。如上图中的2号点。于是设置ssthresh = cwnd / 2、cwnd = 1。此时进入慢开始。在快重传算法中,接收方需要对发送方的数据立即做出确认,即使是失序且已接受的报文段也要做重复确认。如果发送方收到连续多条重复确认,发送方知道了只是丢失了个别报文段,于是开启快恢复

快恢复算法

使ssthresh = cwnd / 2,同时设置cwnd = ssthresh,并开始执行拥塞避免算法

路由器主动队列管理AQM

前面讨论的TCP拥塞控制并没有和网络层采取的策略联系起来。网络层的策略对TCP影响最大的就是路由器的分组丢弃策略。路由器会维护一个先进先出的队列,当队列已满,后续排队的分组都将被丢弃。这就叫做尾部丢弃策略

主动队列管理AQM(active Queue Management) 可用由不同的实现方法。其中**随机早期检验RED(Random Early Edtection)**是其中比较流行的。使用RED需要路由器维护两个参数:最小门限和最大门限。当每一个分组到达的时,RED就按照规定的算法先计算当前的平均队列的长度。并按照一下三种情况处理新的分组:

  1. 平均队列的长度 < 最小门限,则把新到的分组放入队列进行排队
  2. 平均队列的长度 > 最大门限,则把新到达的分组丢弃
  3. 最小门限 < 平均队列的长度 < 最大门限,按照一定的概率p,把新到达的分组丢弃(体现了分组丢弃的随机性)。

RED随机丢弃分组(对应第三种情况),是因为检测到网络拥塞的早期征兆。

参考

  • 《计算机网络 第7版》
  • 《计算机网络 第8版》
  • TCP的流量控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/344289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4.8 注解与自定义注解

文章目录1.概述2.注解的分类2.1 JDK注解2.2 元注解2.2.1 Target ElementType…2.2.2 Retention RetentionPolicy…3 自定义注解1.概述 在注解刚出现时&#xff0c;曾受到过好多程序员的鄙夷&#xff0c;觉得这就是多此一举的操作&#xff1b; 但随着时间的推移&#xff0c;越…

电子技术——电流镜负载的差分放大器

电子技术——电流镜负载的差分放大器 目前我们学习的差分放大器都是使用的是差分输出的方式&#xff0c;即在两个漏极之间获取电压。差分输出主要有以下优势&#xff1a; 降低了共模信号的增益&#xff0c;提高了共模抑制比。降低了输入偏移电压。提升了差分输入的增益。 由于…

【单目标优化算法】食肉植物优化算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

vant 4 正式发布,支持暗黑主题,那么是如何实现的呢

2022年10月25日首发于掘金&#xff0c;现在同步到公众号。11. 前言大家好&#xff0c;我是若川。我倾力持续组织了一年多源码共读&#xff0c;感兴趣的可以加我微信 lxchuan12 参与。另外&#xff0c;想学源码&#xff0c;极力推荐关注我写的专栏《学习源码整体架构系列》&…

八股文总是忘?一张图牢记JVM内存结构|金三银四系列

金三银四又来啦&#xff01;八股文还是得复习起来&#xff0c;最近准备把一些常见的八股文知识点聊聊。本文详解了JVM内存结构和各个部分详细内容&#xff0c;应付面试绰绰有余&#xff01;点击上方“后端开发技术”&#xff0c;选择“设为星标” &#xff0c;优质资源及时送达…

visual studio2022配置opencv

标题&#xff1a;在vs下配置使用opencv 流程&#xff1a; 1、下载安装opencv 2、添加环境变量 3、vs中配置属性 4、使用 5、可能遇到的报错和解决 1、 下载安装opencv 官网下载地址&#xff1a; https://opencv.org/releases/ 我这里是windows环境&#xff0c;所以选择点击w…

Java数据结构之优先级队列

前言总是忘了优先队列的一些应用&#xff0c;其实这都是很基础的了。为了再加强印象&#xff0c;抄一遍吧。PriorityQueue简介PriorityQueue&#xff0c;即优先级队列。优先级队列可以保证每次取出来的元素都是队列中的最小或最大的元素&#xff08;Java优先级队列默认每次取出…

微信小程序 if语法、for循环 条件渲染、列表渲染等讲解

这篇文章我想给大家学习的就是如何使用 if 去判断 组件的是显示和隐藏&#xff0c;如何使用for循环来渲染列表等重复的内容。 1.if语法的使用 在小程序中&#xff0c;我们可以使用wx:if"{{条件}}"来判断是否需要渲染该代码块 也可以用 wx:elif 和wx:else 来添加 el…

【java】Spring Boot -- Spring的IOC实现原理

文章目录IOC定义理解IOC不使用IOC&#xff1a;使用IOC&#xff1a;使用IOC的好处IOC提供被依赖对象的方式构造器注入setter 方法注入接口方式注入简单模拟IOC总结IOC定义 IoC 全称为 Inversion of Control&#xff0c;翻译为 “控制反转”&#xff0c;它还有一个别名为 DI&…

【Selenium】十分钟手把手带你学会WebDriver API

目录 1、定位元素【8种】 2、操作测试对象 3、添加等待 4、弹窗类型 5、浏览器的操作 6、键盘事件 7、选择框 8、上传文件 1、定位元素【8种】 元素定位是自动化测试的核心&#xff0c;想要去操作一个对象&#xff0c;第一步就是需要我们先去识别这个对象。每个对象就会…

全民ChatGPT热:快来解锁你的“全能网友”

前 言 2021年11月30日&#xff0c;OpenAI推出人工智能聊天原型ChatGPT&#xff0c;赚足了眼球&#xff0c;在AI界引发了类似AIGC让艺术家失业的大讨论。 据报道&#xff0c;ChatGPT在开放试用的短短几天&#xff0c;就吸引了超过 100 万互联网注册用户。并且社交网络流传出各种…

html5标签

图片&#xff1a;image 主要属性&#xff1a; src&#xff1a;源属性的值是图像的 URL 地址。 alt&#xff1a;用来为图像定义一串预备的可替换的文本。 注意事项&#xff1a; 注意: 假如某个 HTML 文件包含十个图像&#xff0c;那么为了正确显示这个页面&#xff0c;需要加…

速通Spring

尚硅谷2023最新版Spring6课程_bilibili 1 Spring 【强制】Spring是什么&#xff1f; 1) Spring是一款主流的Java EE轻量级开源框架。 轻量级&#xff1a;体积很小&#xff0c;且不需要依赖于其他组件。 2) 狭义的Spring。 Spring Framework。 3) 广义的Spring。 以Spring F…

python对多个csv文件进行合并(表头需一致)

之前写过python对【多个Excel文件】中的【单个sheet】进行合并&#xff0c;参考&#xff1a;点我 之前也写过python对【多个Excel文件】中的【多个sheet】进行合并&#xff0c;参考&#xff1a;点我 今天再写一个python对多个csv格式的文件进行合并的小工具 但是大家切记&am…

GIS开源框架:ArcGIS文件地理数据库(GDB)解析与入库

对于GIS专业毕业的同学&#xff0c;想必对于ArcGIS软件不会太陌生&#xff0c;对于地理数据库也有一定的了解和使用经验。但是&#xff0c;撇开软件操作层面不谈&#xff0c;作为一个WebGIS/GIS开发人员&#xff0c;我们如何通过GIS开源框架去完成地理数据库的自动化解析和入库…

解决不同影像裁剪后栅格数据行列不一致问题

前言在处理栅格数据时&#xff0c;尽管用同一个矢量文件裁剪栅格数据&#xff0c;不同数据来源的栅格行列数也会出现不一致的情况。如果忽略或解决不好&#xff0c;会导致后续数据处理出现意想不到的误差或错误&#xff0c;尤其是利用编程实现数据处理时。因此&#xff0c;应当…

VisualGDB 5.6R9 FOR WINDOWS

Go cross-platform with comfort VisualGDB 是 Visual Studio 的一个非常强大的扩展&#xff0c;它允许您调试或调试嵌入式系统。这个程序有一个非常有吸引力的用户界面&#xff0c;它有许多调试或调试代码的功能。VisualGDB 还有一个向导可以帮助您调试程序&#xff0c;为您提…

【C++】关键字、命名空间、输入和输出、缺省参数、函数重载

C关键字(C98)命名空间产生背景命名空间定义命名空间使用输入&输出缺省参数什么叫缺省参数缺省参数分类函数重载函数重载概念C支持函数重载的原理--名字修饰C关键字(C98) C总计63个关键字&#xff0c;C语言32个关键字。 下面我们先看一下C有多少关键字&#xff0c;不对关键…

Linux 解压JAR包 查看class内容

快速解决方案 查询class相对路径&#xff1a;jar tf test.jar | grep "test.class"单独解压class文件&#xff1a;jar xvf test.jar com/test/test.class查看class文件内容&#xff1a;javap -c com/test/test.class 背景 服务运行后&#xff0c;日志打印出来发现…

【taichi】利用 taichi 编写深度学习算子 —— 以提取右上三角阵为例

本文以取 (bs, n, n) 张量的右上三角阵并展平为向量 (bs, n*(n1)//2)) 为例&#xff0c;展示如何用 taichi 编写深度学习算子。 如图&#xff0c;要把形状为 (bs,n,n)(bs,n,n)(bs,n,n) 的张量&#xff0c;转化为 (bs,n(n1)2)(bs,\frac{n(n1)}{2})(bs,2n(n1)​) 的向量。我们先写…