【JavaEE初阶】滑动窗口和流量控制以及拥塞控制

2024-08-24 09:04

本文主要是介绍【JavaEE初阶】滑动窗口和流量控制以及拥塞控制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

📕引言

🎄为什么出现滑动窗口

🎋滑动窗口丢包问题

🚩情况一:数据包已经抵达,ACK被丢了

🚩情况二:数据包就直接丢了

🌲流量控制(安全机制)

🌳拥塞控制(安全机制)


📕引言

前面我们讲到的确认应答,超时重传,连接管理都是用来保证TCP可靠传输的机制。那么TCP除了保证可靠传输之外,也希望能够尽可能的保证高效的完成数据传输。

🎄为什么出现滑动窗口

了解确认应答策略的人都知道,对每一个发送的数据报,都要给一个ACK确认应答。收到ACK后再发送下一个数据段。这样做有一个比较大的缺点,就是性能较差。尤其是数据往返的时间较长的时候。

这就是没有引入滑动窗口数据传输的过程,A这边每次要收到ACK才会发送下一个数据,大部分时间都消耗在等待上面了。

引入滑动窗口:

那我们就想,既然这样一发一收的方式性能较低,那么我们一次发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了)。虽然是批量发送,还是要等待一会儿ACK。

滑动窗口的理解:

窗口就相当于你一次能带饭的数量,TCP的窗口大小表示的是:

  • 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000
    个字节(四个段)。(窗口大小是可变,后序解释)

  • 发送前四个段的时候,不需要等待任何ACK,直接发送;

  • 收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据;依次类推;

  • 操作系统内核为了维护这个滑动窗口,需要开辟 ==发送缓冲区 ==来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉(后面丢包是会有作用)

  • 窗口越大,则网络的吞吐率就越高;

注意:假如当确认应答时,发送方收到的是3001,没有收到2001,这里没有冲突,意味着发送方对于3001之前的所有数据都得到了确认。那么此时滑动窗口就一下跳两格。

问题来了,如果出现了丢包,如何进行重传?

🎋滑动窗口丢包问题

滑动窗口虽然为了提升效率,但是前提是保证可靠传输。

我们这里分为两种情况来讨论

🚩情况一:数据包已经抵达,ACK被丢了

发送的数据包已经抵达,回应报文ACK却丢了

这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认;

这是因为ACK应答报文上的确认序列号表示的是,该字节序以前的报文一全部到达,请下一条报文从该字节序开始。

就比如上图中的1001丢了,但是收到了2001,也就代表2000以前的数据已经全部收到了。所以此时是否收到1001已经无所谓了

🚩情况二:数据包就直接丢了

比如下属情况,1-1000的数据包丢了

当1001-2000报文段丢失之后,虽然主机A一直在给主机B往后发送数据,但是接收端一直没有收到1001这段的数据报,就会一直向发送端索要1001的数据

发送端发现连续三次收到了接收端发来同样一个 “1001” 这样的应答,他就明白了这段数据丢了,就会将对应的数据 1001 -2000 重新发送;

这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中;

结论:

滑动窗口说是"提升效率"的机制,更准确的说,是"亡羊补牢"的机制,TCP为了保证可靠性,牺牲了很多效率,引入滑动窗口,是效率上的牺牲变少一些,但是仍然是存在牺牲的,在怎么滑动窗口,速度不可能比UDP这种没有可靠机制的协议更快。

窗口大小是可变的,可以通过窗口大小,来控制发送方的速度,窗口越大,单位时间发送的数据越多,越高效,窗口越小,单位时间发送的数据越少。通常情况下,认为尽可能的高效传输,但是高效的前提是可靠,如果传输的速度太快,接收方处理不过来,此时也会引起丢包。

那么我们如何设置窗口的大小呢?这就不得不提到我们下面讲的两种机制:流量控制、拥塞控制

我们的窗口大小就是由这两个决定的,两者取最小

详细机制介绍如下所示:

🌲流量控制(安全机制)

接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。

因此TCP支持根据接收端的处理能力,来决定发送端的发送速度。这个机制就叫做流量控制(Flow Control)

具体如何衡量接收方的处理速度呢?

接收方有一个接收缓冲区(阻塞队列):

就会把窗口大小的数值告诉发送方,如何告诉呢?接收方会返回ACK,在ACK的报文中,在TCP报头里,指定一个字段,表示上述的空间大小,这个字段这个是报头中的16位窗口大小。

发送方就可以按照上述窗口大小,决定下一轮数据发送的窗口大小了。

  • 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段,通过ACK端通知发送端;
  • 窗口大小字段越大,说明网络的吞吐量越高;
  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
  • 发送端接受到这个窗口之后,就会减慢自己的发送速度;
  • 如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据
  • 若B的缓冲区发生改变(应用程序消费了一部分数据),这时候需要发送方会定期发送一个窗口探测数据段(不携带载荷),从而触发ACK,知道B这边的缓冲情况,接收端把窗口大小告诉发送端。

🌳拥塞控制(安全机制)

拥塞控制和流量控制类似,都是和滑动窗口搭配的机制。

流量控制是站在接收方的角度从而影响发送方的速度。但是呢,发送方发得有多快,不光要考虑接收方的接收能力,还要考虑中间的路由器/交换机是否能接受。中间这些机器的处理能力是不确定的,链路上的任何一个节点,性能瓶颈都会制约发送方的发送速度。在不清楚当前网络状态下,贸然发送大量的数据,是很有可能引起雪上加霜的。

流量控制的时候,很容易定量的来衡量接收缓冲区剩余空间的大小,这个作为发送窗口的大小。但是考虑中间节点就比较复杂,中间有多少设备?每次走的路径可能都不一样,每个设备的处理能力,繁忙程度都不一样......

那么我们就可以不管你中间结构有多复杂,tcp都把他们视为一个整体,然后通过"实验"的方式,找到一个合适的窗口大小(发送速度)。

流程:

具体流程:

TCP引入 慢启动 机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据;

  • 此处引入一个概念称为拥塞窗口
  • 发送开始的时候,定义拥塞窗口大小为1;
  • 每次收到一个ACK应答,拥塞窗口乘以2;
  • 每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口;

像上面这样的拥塞窗口增长速度,是指数级别的。

慢启动” 只是指初使窗口大小比较小,传输速度慢,但是增长速度非常快。

  • 为了不增长的那么快,因此不能使拥塞窗口单纯的加倍。
  • 此处引入一个叫做慢启动的阈值
  • 当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长
  • 线性增长也是增长,增长到一定程度,就会出现丢包,此时发送方就知道网络大概的能力是在啥样的水平,此时就会把窗口变小(发送速度减下去)

  • 直接缩到底(回到慢启动的时候),接下来指数增长-线性增长;缩到出现丢包的时窗口一半这样的位置,接下来线性增长
  • 当TCP开始启动的时候,慢启动阈值等于窗口最大值
  • 在每次超时重发的时候,慢启动阈值会变成原来最大窗口的一半,同时拥塞窗口置回1

注意:

  • 少量的丢包,我们仅仅是触发超时重传;大量的丢包,我们就认为网络拥塞;
  • 当TCP通信开始后,网络吞吐量会逐渐上升;随着网络发生拥堵,吞吐量会立刻下降;

最终流量控制的窗口大小和拥塞控制的窗口大小,谁小就取谁。

拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。

这篇关于【JavaEE初阶】滑动窗口和流量控制以及拥塞控制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1102034

相关文章

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

SpringBoot操作spark处理hdfs文件的操作方法

《SpringBoot操作spark处理hdfs文件的操作方法》本文介绍了如何使用SpringBoot操作Spark处理HDFS文件,包括导入依赖、配置Spark信息、编写Controller和Ser... 目录SpringBoot操作spark处理hdfs文件1、导入依赖2、配置spark信息3、cont

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

Java中的密码加密方式

《Java中的密码加密方式》文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固... 目录Java的密码加密方式密码加密一般的应用方式是总结Java的密码加密方式密码加密【这里采用的

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

《解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题》本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常... 目录myBATis-plus-boot-starpythonter与mybatis-spring-b