【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

相关文章

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明