新手建站详细步骤/seo软件安卓版
TCP 全称为 Transmission Control Protocol(传输控制协议),是一种面向连接的、可靠的、基于字节流的传输层通信协议,其中可靠性是相对于其他传输协议的优势点。TCP 为了确保数据传输的可靠性主要做了以下几点:
- 发送确认机制
- 丢包重传机制
- 滑动窗口
- 拥塞控制
TCP 的传输基于字节流,记录起始序列号、是否发送、是否接收。本文从实战出发,使用 Wireshark 抓包工具来分析具体的请求。
确认和重传
- TCP 报文头中有两个字段:
- Sequence number 序列号:表示要发送数据的起始号
- Acknowledgment number 确认号:表示消息已经接收,返回下次要发送的起始号
发送确认
TCP 每次发送数据,都有一个确认应答 ACK,表示已经收到了数据包。确认号表示下一个传送的起始号。
发送一个 http 请求,使用 Wireshake 抓取数据包,打开 Statistics -> Flow Graph,在弹出的页面上将 Flow type 修改成 TCP Flows,就能看到 TCP 的数据包请求:
上图中标记了三个地方,中间的的标记的发送确认,就表示数据发送和确认应答,len 表示字节长度。发送 1 ~ 218 的字节,确认应答返回了确认号 219。第二个发送确认也是类似原理,所不同的是,这个发送确认时接收端的发送确认。
重传机制
发送端的数据包,一般都发送到接收端。但是在网络不好,或者信号比较差的情况,可能就无法正常发送到数据。
先介绍两个概念,RTT 和 RTO。
RTT Round-Trip Time 表示往返时间,表示网络一段到另一端所需要的时间,也就是数据包的往返时间,以 TCP 握手为例:
RTT 表示数据包从发送到收到确认应答的时间。
RTO Retransmission Timeout 表示超时重传时间。超过这个时间没有确认应答,就会重传报文段,这个时间根据 RTT 来设置的。
重传机制是 TCP 基本的错误恢复功能,常见的重传机制有两种:
- 超时重传
- 快速重传
1、超时重传
超时重传,字面意思是,超时规定的时间没有收到确认消息,就会再次发送一个消息请求。TCP 发送方发送报文时,会设置一个定时器,如果在时间范围内没有收到接收方发来的 ACK 确认报文,发送方就会重传已经发送的报文段。
TCP 有两种超时重传的情况:
- 报文在发送途中丢失
- 确认包在途中丢失
上面的 RTO 表示超时重传时间,RTO 的设定不能过大的或者过小:
- 如果过大,请求等待的时间过长,请求的效率低。
- 如果过小,正常返回的确认还未来得及返回,就重传。加大网络符合。
设置一个适当的 RTO 才会让重传机制更加高效。超时时间 RTT 应该略大于往返时间 RTT。
如果超时重传的报文段又超时了该怎么办呢?,答案就是重传的超时时间加倍,也就是再次超时重传的超时时间会增加到之前的两倍。
如果超时重传的报文段又丢包呢?此时发送方会以 RTO 时间的 2、4、8倍的倍数尝试多次重传。
超时重传如果消息多次没有收到确认报文,超时的周期也比较长,有没有更加高效的方法减少超时重传的时间呢?就引出下面的要讲的快速重传。
快速重传
快速重传不会等待超时时间到了再重传,发送方收到 3 次重复确认报文端,就不会等超时时间重试,而是直接重传报文。
连续发送的报文段,中间只要有一个丢失,后续返回的确认号都是相同,后面的报文段无论有没有返回,都会重传一遍,这种设置还是比较合理的。在一段时间内,如果网络状况不好,导致丢包情况,后续的报文段一般也会丢包。
但是重传丢包后面所有的包,也会造成网络传输的浪费。对于上面的例子,如果只想传输 seq2,其他有返回的确认包就不用重传。
TCP 有一种重传机制: SACK Selective Acknowledgment 选择性重传。
这种方式需要 TCP 报文段选项加一个 SACK 字段,使用查看 Wireshake SYN 包中 SACK Permitted:
发送包有返回确认应答,就会发送给发送方告知对应的数据被接收了,发送方就能记录哪些数据被接收了,哪些数据没有被接收。后面只会重传没有被接收的数据包,这就是选择性重传。
滑动窗口
TCP 发送比较大的数据包,TCP 会一次性发送大的数据包给接收方?答案是不会的,需要考虑网络带宽,TCP 会将大的数据包拆分成多个大小适中的数据包,发送一个 http 请求,添加较大的参数,使用 Wireshake 抓取数据包:
数据包被拆分成五个小的数据包。
数据包被拆分成多个小的数据包之后,数据包发送都有返回一个确认序列号,每次发送一个新的包,都等待上一个包的 ACK 回来之后才能发送,这样一来一回的效率是很低的:
TCP 为了解决这个问题,引入窗口的概念,在窗口范围内的数据包,无需等待上一次 ACK 确认,可以直接发送数据包:
滑动窗口是 TCP 协议中的一种流量控制机制,用来控制发送方和接收方数据传输的速率,避免数据过多造成数据无法及时处理。
窗口的大小也就是 TCP 报文段的 windos 字段,表示的就是接收方目前能接收的缓冲区的剩余大小,发送端根据这个字段处理发送的数据。
发送端的窗口
发送窗口根据三个标准来划分:是否发送、是否收到 ACK、是否在接收方处理范围内,分成了四个部分:
四个部分组成:
- 第一部分是已经发送并收到 ACK 确认的数据,这部分数据已经发送成功了,无需在缓存中保留了。
- 第二部分数据是已经发生但是未收到 ACK 确认的数据。
- 第三部分数据是未发送,但是在接收方处理范围之内的数据。第二、第三部分共同组成发送的窗口。
- 第四部分是需要发送,但是未在接收方范围之内的数据。这部分数据在没有接收 ACK 确认之前,是不会发送数据的。
如果发送方一直没有收到 ACK,数据不断的发送,很快可用窗口也被耗尽,这时发送方也不会继续发送数据了,这时发送端可用窗口为零的情况我们成为“零窗口”。
随着 ACK 的确认,窗口也会依次向右滑动,比如发送端的窗口中,比如 40 ~ 43 字节都收到了 ACK 确认,那么整个可用的窗口就会顺次往右移动。此时 53 ~ 57的数据也都能发送了。
接收端的窗口
接收端的滑动窗口相对发送的窗口要简单的多,主要分为三个部分:
- 已经接收并确认的数据
- 可以接收但是未接收的数据
- 在接收范围之外(不够缓存的数据),也就是不可以接收的数据。
但数据接收后,窗口也向右边滑动,给发生端的数据提供数据缓存。如果读取缓存的数据速度有变化时,接收端可能也会改变接收窗口的大小,以此来控制发送端的发送速度。这就是滑动窗口进行流量控制的一种机制。
拥塞控制
网络中由于有大量的包传输,在固定带宽下处理不过来数据包的传输,可能会导致数据包阻塞,网络传输的速度下降,甚至会下降到 0 的情况。这就有点类似排队买东西,如果正常排队,速度虽然不快但处理速度比较稳定。但是如果一下涌来很多人口,就会处理不过来,导致堵死情况。
而 TCP 被设置成一个无私的协议,当遇到网络拥塞时,TCP 会减少自己发送数据包,这样网络拥塞会得到很大的缓解。
为了实现拥塞控制,首先在发送端定义一个拥塞窗口 CWND (congestion window),限制发送端发送数据最多没有收到 ACK 确认包的大小,超过拥塞窗口范围后,就不会继续发送数据了。
拥塞窗口会随着网络情况的变化动态的调用自身的大小,大体的变化规则是:如果没有出现拥塞,就扩大窗口大小,否则就缩小窗口的大小。
拥塞控制算法主要包含四个部分:
- 慢启动
- 拥塞避免
- 拥塞发生
- 快速恢复
慢启动
当一个新的TCP连接开始时,无法确定是否用拥塞发生,一开始不会发送大量的包,而是从最小的发送窗口开始,后续会采用倍增的方式增加窗口的大小,窗口大小从 1 开始,后续慢慢增大到 2、4、8 等。
指数增加速度会越来越快,窗口扩大的一定的程度,就会减慢增加的速度,改成线性增加,这时候就进入拥塞避免阶段。
拥塞避免
慢启动和拥塞避免的临界点叫做慢启动门限 ssthresh (slow start threshold。
- cwnd < ssthresh 时,使用慢启动算法。
- cwnd >= ssthresh 时,就会使用「拥塞避免算法」。
ssthresh 大小一般是 65535 字节。拥塞避免的规则是:每当收到一个 ACK 时,cwnd 增加 1/cwnd。就变成线性增长了。
拥塞发生
拥塞避免将原来的指数增长改成了线性增长,虽然增长速度减慢,但 CWND 窗口还是在增长阶段。随着窗口进一步缓慢增加,网络还是会遇到阻塞的状态,会出现丢包的情况。就需要对丢包进行重传。
重传机制有两种:
- 超时重传
- 快速重传
当发生超时重传时,sshresh 和 cwnd 的值会发生如下变化:
- sshresh 变成 cwnd 的一半
- cwnd 重置为 1
cwnd 重置为1,表示直接进入慢启动状态。
上面的超时重传速度变化太快,而快速重传是一个相对温和的方案。如果我们连续 3 次收到同样序号的 ACK,包还能回传,说明这个时候可能只是碰到了部分丢包,网络阻塞还没有很严重,无需重置 cwnd。
此时 ssthresh 和 cwnd 变化如下:
- cwnd = cwnd/2 ,也就是设置为原来的一半;
- ssthresh = cwnd
并进入到快速恢复阶段。
快速恢复
快速恢复主要是将 cwnd 恢复到正常大小,上面说的 cwnd 设置成原来的一半,ssthresh 设置成 cwnd 的大小。
快速恢复算法如下:
- 重传丢失的数据包。
- 如果接收到重复 ACK 确认,cwnd 增加 1。
- 如果接收到新数据的 ACK 确认,就将 ssthresh 恢复到慢启动时期的值,因为返回新数据的 ACK 确认,表示网络阻塞已经结束,可以恢复到之前的状态,cwnd 也可以指数或者线性增加。
总结
TCP 提供基于字节流、可靠的数据传输,为了确保数据的可靠性,做了很多工作:
- 报文段序号和确认号
- 每个报文都有序号和确认号,序号表示报文段第一个字节号,确认号表示下一个接收字节的序号。
- 发送确认和重传机制
- 每个报文段发送后,都会确认应答 ACK,表示已经报文段已经成功发送。
- 当网络异常数据包无法达到时,就会触发重传机制。重传主要有两种方式:超时重传和快速重传。
- 超时重传:设置一个定时器,超过时间未收到确认应答,就会重新传数数据包。这个重传方式周期比较长。
- 快速重传:快速重传不会等待超时时间到了再重传,是以数据为基点,发送多次报文段,当接受到重复的确认应答号 ACK 时,直接重传所有的报文段。可以使用 SACK 记录哪些报文段已经成功接收了,只重传没有被成功接收的报文段。
- 滑动窗口
- 报文段拆分,TCP 将要发送的数据拆分适当大小的数据包。
- 引入窗口的概念,这个窗口大小是由接收方来决定,表示接收方可以接收的缓存大小。在窗口范围之内, TCP 可以连续发送多个数据包给接收方,当数据包发送并且有确认应答,整个窗口会往后移动,继续发送新的数据。
- 随着数据传输的速度和网络情况,接受方可能会动态修改窗口的大小,以此来控制数据传输的速度。
- 滑动窗口能流量进行控制,控制数据发送的速度和频率,避免出现拥塞情况。
- 拥塞控制,在网络传输中可能会出现大量的数据请求,而固定的网络宽带可能处理不过来这么多数据传输,容易形成阻塞的情况。TCP 遇到网络拥塞时,会自动减少自己发送包的数量,这样网络拥塞情况就会缓解。TCP 发送端定义拥塞窗口 CWND,表示没有接收到 ACK 确认数据的最大发送量。拥塞控制算法主要包含四个部分:
- 慢启动:开始一个新的连接时,从较小的发送窗口开始,然后指数增长增加 CWND 窗口大小,知道达到慢启动门限。
- 拥塞避免:窗口达到慢启动门限临界点时候,慢启动阶段结束,这个阶段,窗口大小线性增加,增长速度比较慢,避免发生网络拥塞。
- 拥塞发生:窗口进一步缓慢增加,网络还是会遇到阻塞的状态,会出现丢包的情况。就需要对丢包进行重传。此时有两种重传机制:超时重传和快速重传。超时重传,是窗口大小重置为 1,数据传输又恢复成慢启动时的速度。这种传输速度急剧下降,不利于系统稳定,由于窗口大小限制,网络传输次数更多,拥塞的情况也会更大。而快速重传是相对温和的方案,此时认为网络只是暂时有阻塞情况,将窗口大小 CWND 改成原来的一半,并进入快速恢复阶段。
- 快速恢复:重传丢失的数据包,如果接收到重复 ACK 确认,cwnd 增加 1。如果接收到新数据的 ACK 确认,就将 ssthresh 恢复到慢启动时期的值,因为返回新数据的 ACK 确认,表示网络阻塞已经结束,cwnd 也可以指数或者线性增加。
参考
-
TCP 重传、滑动窗口、流量控制、拥塞控制
-
滑动窗口:TCP是如何进行流量控制和拥塞控制的
相关文章:

TCP的可靠性之道:确认重传和流量控制
TCP 全称为 Transmission Control Protocol(传输控制协议),是一种面向连接的、可靠的、基于字节流的传输层通信协议,其中可靠性是相对于其他传输协议的优势点。TCP 为了确保数据传输的可靠性主要做了以下几点: 发送确…...

基于spring boot校园疫情信息管理系统/疫情管理系统
摘要 随着计算机技术,网络技术的迅猛发展,Internet 的不断普及,网络在各个领域里发挥了越来越重要的作用。特别是随着近年人民生活水平不断提高,校园疫情信息管理系统给学校带来了更大的帮助。 由于当前疫情防控形势复杂ÿ…...

使用Python批量将飞书文档转为MD
说明:飞书是在线文档平台,本文介绍如何使用Python程序批量将飞书文档转为MD文档,并下载到本地; 复制地址 首先,把文档的URL都复制下来,这个需要一个一个点,并复制拷贝,但却是工作量…...

Nacos配置管理、Feign远程调用、Gateway服务网关
1.Nacos配置管理 1.1.将配置交给Nacos管理的步骤 1.在Nacos中添加配置 Data Id服务名称-环境名称.yaml eg:userservice-dev.yaml 2.引入nacos-config依赖 在user-service服务中,引入nacos-config的客户端依赖 <!--nacos配置管理依赖--> <dep…...

解决Spring Boot前后端分离开发模式中的跨域问题
在实际开发中,经常会遇到前端Vue应用与后端Spring Boot API接口存在跨域访问的问题。本篇博客将分享解决Spring Boot前端Vue跨域问题的实战经验,帮助开发者快速解决该问题。 一、跨域问题的原因 跨域问题是由于浏览器的同源策略引起的。同源策略限制了…...

常见前端面试之VUE面试题汇总五
13. assets 和 static 的区别 相同点: assets 和 static 两个都是存放静态资源文件。项目中所 需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件 下,这是相同点 不相同点:assets 中存放的静态资源文件在…...

带着问题看SpringBoot
带着问题看SpringBoot 1、Spring容器具体是什么? 跟进run方法,context this.createApplicationContext(),得出容器是AnnotationConfigServletWebServerApplicationContext类。 SpringApplication.run(ServeroneApplication.class, args);…...

【Go 基础篇】Go语言匿名函数详解:灵活的函数表达式与闭包
介绍 在Go语言中,函数是一等公民,这意味着函数可以像其他类型的值一样被操作、传递和赋值。匿名函数是一种特殊的函数,它没有固定的函数名,可以在代码中被直接定义和使用。匿名函数在Go语言中具有重要的地位,它们常用…...

MobileNet、MobileNetV2和MobileNetV3创新点总结
当谈论MobileNet、MobileNetV2和MobileNetV3时,我们指的是一系列基于深度学习的轻量级神经网络架构,这些架构旨在在保持高度准确性的同时减少模型的计算和参数量。以下是它们各自的创新点的详细总结: MobileNet: 深度可分离卷积&…...

算法:数据转换处理2(云台显控)
#define DISPLAYFUNC #include"define.h" extern OS_EVENT *KEYMsg; uchar mBlank[21] = " " ; u c h a r s t r v g a [ ] = " 0.00 V "; uchar str_vga[] = "0.00V...

让大数据平台数据安全可见-行云管家
数字化经济在快速发展,大数据时代已经到来,大数据已经成为企业和政府决策的重要依据。然而大数据行业快速发展所带来的一系列安全问题也继续解决,例如数据安全更难保障,例如认证体系不完善等等。为此行云管家推出了大数据平台数据…...

微信小程序开发教学系列(3)- 页面设计与布局
3. 页面设计与布局 在微信小程序开发中,页面的设计和布局是非常重要的。一个好的页面设计可以提升用户体验,并使小程序更加吸引人。本章节将介绍如何设计和布局微信小程序的页面。 3.1 页面结构和样式的创建和设置 在创建微信小程序页面时,…...

基于JSP+Servlet+mysql员工权限管理系统
基于JSPServletmysql员工权限管理系统 一、系统介绍二、功能展示四、其他系统实现五、获取源码 一、系统介绍 项目类型:Java web项目 项目名称:基于JSPServlet的员工权限管理系统[qxxt] 项目架构:B/S架构 开发语言:Java语言 …...

Qt 自定义提示框 右下角冒泡
网页右下角上经常会出现一些提示性的信息,B/S有的东西,C/S当然也可以有,就像QQ的消息提示一样! 实现一个类似的东西并不困难,只要想明白原理实现起来就很简单了! 实现原理: (1&#…...

js、PHP连接外卖小票机打印机方案(调用佳博、芯烨等)
前言: 目前开发需要用到电脑直接连接外卖小票机打印小票,查阅各种资料,使用 6612345浏览器 终于解决了这个问题。 效果: PHP、js直接连接小票机并且自动出票。 支持的小票机: 目前测试可以的有:电脑A4打印…...

window定时备份MySQL数据库,默认备份7天,一小时备份一次
echo off setlocalrem 在Windows中添加任务计划以执行批处理脚本,请按照以下步骤操作:rem 打开Windows的“任务计划程序”应用程序。你可以通过按下Win R键,在运行对话框中输入taskschd.msc,然后按回车键来打开它。rem 在任务计划…...

正则中常见的流派及其特性
目前正则表达式主要有两大流派(Flavor):POSIX 流派与 PCRE 流派。 1、 POSIX 流派 POSIX 规范定义了正则表达式的两种标准: BRE 标准(Basic Regular Expression 基本正则表达式);ERE 标准&am…...

.net6.0引用的dll放置单独的文件夹
.net6.0 采用原有的设置方法不起作用 <?xml version"1.0" encoding"utf-8" ?> <configuration><startup> <supportedRuntime version"v4.0" sku".NETFramework,Versionv4.8" /></startup><runtim…...

CMake:检测外部库---自定义find模块
CMake:检测外部库---自定义find模块 导言项目结构CMakeLists.txt附录 导言 上一篇,我们了解了CMake其中一种自定义检测外部库的方式,本篇将展示通过编写一个find模块来定位系统上的ZeroMQ库,以便能够在非Unix操作系统上检测该库。 项目结构…...

vue直接使用高德api
第一步:在index.html 引入 <script src"https://webapi.amap.com/maps?v2.0&key你的key"></script>第二步:在你需要地图的时候 放入 <template><div style"width: 200px; height: 200px"><div id&q…...

Setting
目录 1 Setting 1.1.1 getChildList 1.1.2 getGroupList 1.1.3 setListener setOnChildClickListenermSettingList.setOnChildClickListener(new OnChildClickListener() {onChildClick...

时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元时间序列预测
时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元时间序列预测 目录 时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化…...

论文浅尝 | KRACL-利用图上下文和对比学习的稀疏KG补全
笔记整理:李娟,浙江大学博士,研究方向为知识图谱表示学习 论文链接:https://arxiv.org/pdf/2208.07622.pdf 代码链接:https://github.com/TamSiuhin/KRACL 介绍 知识图谱(KG)通常是不完整的&…...

【C++】右值引用,移动语义,完美转发
目录 右值引用移动语义拷贝构造与移动构造 万能引用与完美转发 右值引用 左值:可以出现在赋值符号的左边和右边,左值可以取地址。 右值:右值可以出现在赋值符号右边,不能出现在左边,右值不能取地址。 左值/右值引用就…...

【AI】即使AI 时代,程序员也无需焦虑
🚀欢迎来到本文🚀 🍉个人简介:陈童学哦,目前学习C/C、算法、Python、Java等方向,一个正在慢慢前行的普通人。 🏀系列专栏:陈童学的日记 💡其他专栏:CSTL&…...

Django实现DRF数据API接口格式封装
通常在进行前后端分离开发的时候,前端Vue调用后端接口都需要一个状态信息以及数据结合起来的数据。 如果是没有经过加工的API接口访问的数据一般是这样的。 [{"id": 1, "type": "1", "start": "2023-08-24", "end&qu…...

[Go版]算法通关村第十三关白银——数字数学问题之数组实现加法、幂运算
目录 数组实现加法专题题目:数组实现整数加法思路分析:数组末尾开始,逐个元素1,10就进位,!10就退出复杂度:时间复杂度 O ( n ) O(n) O(n)、空间复杂度 O ( n ) O(n) O(n)Go代码 题目:字符串加法…...

【 OpenGauss源码学习 —— 列存储(Insert)】
列存储(Insert) 概述相关函数ExecInsertRelationData 结构体FormData_pg_class 结构体HeapInsertCStore函数InsertArg 结构体CStoreInsert 类CStoreInsert::InitInsertArg函数heap_deform_tuple 函数bulkload_rows 结构体append_one_tuple 函数bulkload_…...

Android 13.0 framework中实现默认长按电源键弹出关机对话框功能
1.前言 在13.0的系统定制化开发中,在12.0的系统之前默认的都是长按电源键弹出关机对话框,而在13以后 就改成音量+电源键弹出对话框,由于使用不方便,所以就改成默认长按弹出关机对话框功能 2.framework中实现默认长按电源键弹出关机对话框功能的核心类 frameworks/base/s…...

微信小程序,封装身高体重选择器组件
wxml代码: // 微信小程序的插值语法不支持直接使用Math <wxs src"./ruler.wxs" module"math"></wxs> <view class"ruler-container"><scroll-view scroll-left"{{scrollLeft}}" enhanced"{{tru…...