【Linux网络】详解TCP协议(3)

图片名称
🎉博主首页: 有趣的中国人

🎉专栏首页: Linux网络

🎉其它专栏: C++初阶 | C++进阶 | 初阶数据结构

在这里插入图片描述

小伙伴们大家好,本片文章将会讲解 TCP的流量控制和滑动窗口 的相关内容。


如果看到最后您觉得这篇文章写得不错,有所收获,麻烦点赞👍、收藏🌟、留下评论📝。您的支持是我最大的动力,让我们一起努力,共同成长!

文章目录

  • `1. 流量控制`
    • ==<font color = blue><b>🎧1.1 流量控制是什么🎧==
    • ==<font color = blue><b>🎧1.2 如何控制发送方的速度🎧==
  • `2. 滑动窗口`
    • ==<font color = blue><b>🎧2.1 什么是滑动窗口🎧==
    • ==<font color = blue><b>🎧2.2 深入理解滑动窗口🎧==



上一篇文章中,博主介绍了 :

  • TCP 的三次握手和四次挥手;

建议将上一篇文章看完之后再来看这篇文章,链接如下:

【Linux网络】详解TCP协议(2)

那么接下来正片开始:



1. 流量控制


🎧1.1 流量控制是什么🎧


  • 接收端处理数据的速度是有限的, 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包;
  • 继而引起丢包重传等等一系列连锁反应;
  • 因此 TCP 支持根据接收端的处理能力, 来决定发送端的发送速度。 这个机制就叫做流量控制(Flow Control)。
  • 总的来说就是根据接收方的接受能力控制发送方发送数据的速度。

🎧1.2 如何控制发送方的速度🎧


  • 如何控制发送方的发送数据的速度分为两种情况:
    • 一种是接收方接收缓冲区太大;
    • 另一种是接收方接收缓冲区太小。

16位窗口大小

  • 首先回顾一下TCP报头:

在这里插入图片描述

  • 在报头中存在 16位窗口大小,这个窗口大小就是接收方用来通知发送方它的接收缓冲区大小而存在的。
  • 当接收方接收缓冲区大,回复的ACK中的窗口大小就大,反之亦然;

那么这个时候很多人可能会有一个疑问,那么在发送方第一次给接收方发送消息的时候是怎么知道窗口大小的呢?

  • 其实虽然是第一次发送消息,但是他们双方在三次握手建立连接的时候,接收方就已经给发送方发送了携带ACK的数据包;
  • 这个时候就已经给发送方通告了接收方接收缓冲区的大小。
  • TCP报文中窗口大小是16位的,那么最大的窗口大小就是 2 16 − 1 = 65535 ( K B ) 2^{16} - 1 = 65535 (KB) 2161=65535(KB),但是真的是这样的吗;
  • TCP报头中,除了 20Byte 的固定的TCP报头大小,还有个40Byte的选项,在这里面包含了窗口扩大因子M实际上的窗口大小就是窗口字段的值左移M位。

PSH 标志位

  • 当接收方接收缓冲区的大小很小,甚至为 0 0 0 的时候,怎么办呢?一般有三种做法:
  • 首先当窗口大小为 0 0 0 的时候,如果过了一段时间接收方的接收缓冲区扩大了,就会给发送方发送一个窗口更新通知,告诉发送方可以发送数据了;
  • 当然,如果过了超时重传的事件之后,方式方还没有接收到窗口大小变化的通知,发送方也会不断地向接收方发送窗口探测的数据包,如果发现接收方回复的ACK的数据包中窗口大小变大了,就会发送数据了;
  • 但是如果接收方的接收缓冲区长时间没有变化,发送方也会发送一个带有PSH标志位的报文,通知接收方得快速地处理接收缓冲区中的数据。

URG标志位

这样看来,我们已经学习了五个标志位,就差最后一个URG标志位了,那我们就来讲解一下URG标志位吧!

  • 如果在TCP报头中URG标志位置 1,说明报头中的16位紧急指针是有效的;
  • 这个紧急指针代表着在TCP的数据中,和首位置的偏移量是多少
  • 一般在TCP中紧急数据只能有 1 B y t e 1 Byte 1Byte

send()recv() 系统调用中都有紧急数据的设置,我们再来看一下接口:

  • ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    • 使用 send() 系统调用发送数据时,可以选择将带外数据发送到指定的套接字。通过设置标志参数中的 MSG_OOB可以标识要发送的带外数据
    • 其中,flags 参数可以传递 MSG_OOB,以指示发送的字节是带外数据。
  • ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    • 使用 recv() 系统调用接收数据时,也可以指定标志以接收带外数据。通过设置标志参数中的 MSG_OOB接收方可以读取带外数据
    • 其中,flags 参数可以传递 MSG_OOB以指示接收带外数据


2. 滑动窗口



在讲解完流量控制和超时重传机制,其实还是有两个问题:

  • 发送方如何根据接收方的窗口大小发送数据呢?
  • 超时时间内,数据并没有被丢弃,那存储在哪里了呢?


为了理解这两个问题,我们得先学习滑动窗口。


🎧2.1 什么是滑动窗口🎧


  • 博主在 TCP第一篇文章 中讲过,发送方可以一次性给接收方发送多条数据,例如下图:

在这里插入图片描述

  • 这样发送数据就可以大大提高效率,因为可以在一个时间段发送多条数据。
  • 而发送方就规定一个概念:滑动窗口,并且在滑动窗口内的数据可以直接发送,暂时不用收到应答。
    • 在窗口左侧的数据就是已发送,已确认了的;
    • 在窗口右侧的数据就是未发送,未确认;
    • 在窗口中的数据就是等待发送的数据。
  • 而滑动窗口的大小就是对方同步给我的接收缓冲区的大小,即对方的接受能力(暂时)。

滑动窗口抽象图

在这里插入图片描述


🎧2.2 深入理解滑动窗口🎧



那么依然有几个问题:

滑动窗口可以变大吗?
滑动窗口可以变小吗?
滑动窗口可以向左移动吗?

OK,那么接下来就来解答这几个问题。


  • 滑动窗口本质上就是对方接受能力的大小,即对方接收缓冲区的大小;
  • 所以如果对方接受能力变大,那么滑动窗口就会变大,反之亦然
  • 如果对方的接收缓冲区中已经没有空间了,即对方接收缓冲区满了,那么滑动窗口的大小自然就变成了 0 0 0
  • 滑动窗口是不能向左滑动的。因为在窗口左边的数据是已发送已确认了的,所以就不可能再重新发送一次了

滑动窗口表示方法

  • 博主之前讲解过,缓冲区可以想象成一个很大的数组,那么缓冲区中的每一个数据就天然有了一个下标;
  • 那么滑动窗口中的数据就也有自己的下标;
  • 当接收方给我回复ACK的时候,在TCP报头中有确认序号,所以这个序号就可以代表窗口的起始地址,而报头中窗口的大小就是滑动窗口的大小
  • 这样我们就可以用几行代码表示窗口的起始地址以及结束地址:
    • win_start = ack_seq;
    • win_end = win_start + win_size;
    • 这样我们就可以直观的理解什么是窗口的变大、变小甚至为 0 0 0,以及为什么不能向左移动;
  • 当然缓冲区的大小不可能是无穷大的,所以在底层应该使用环形队列来实现的,可能会用取模运算来实现

滑动窗口丢包问题

如果滑动窗口中有数据丢包应该怎么办呢?丢包起始可以分成三种情况:

  • 头部丢包;
  • 中间丢包;
  • 为不丢包;
  • ACK丢包

先来看一下头部丢包:

在这里插入图片描述

  • 确认序号的定义是表示接收端这个序号之前的所有数据我已经收到了;
  • 那么假设头部丢包,接收方发给发送方的TCP报文中,确认序号就一直是 0 0 0(上图的情况)。
  • 那么发送方接收到所有报文中确认序号就都是 0 0 0(上图的情况);
  • 当发送方接收到连续三条相同的确认应答,就会进行重传;
    • 这种机制叫做快速重发机制,又称为快重传。
    • 快重传机制和超时重传机制并不冲突,超时重传机制相当于是给快重传机制兜了底。
  • 上图如果发生了快重传,并且接收方接收到了数据,那么下一次的确认序号就是 8001 8001 8001

中间数据和尾部数据丢包:

  • 当中间数据或者尾部数据丢包,那么发送方收到的确认序号就是丢包的那个部分的开始序号
  • 由于滑动窗口的起始地址就是等于确认序号,因此丢包的那部分数据就变成了头部,进而全部转换成了头部数据丢包。

ACK丢包:

在这里插入图片描述

  • 这种情况并不要紧,因为可以通过后续的ACK确认接收方是否收到了。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

性能测试学习1:性能测试的理论与目的,与功能测试的区别

一.什么是性能&#xff1f; 1&#xff09;性能&#xff1a;就是软件质量属性中的“效率”特性 2&#xff09;效率特性: ①时间特性&#xff1a;表示系统处理用户请求的响应时间【通俗来说&#xff0c;就是使用系统是否流畅】 ②资源特性&#xff1a;表示系统运行过程中&…

锐捷 NBR 1300G路由器 越权CLI命令执行漏洞

漏洞描述 锐捷NBR 1300G路由器 越权CLI命令执行漏洞&#xff0c;guest账户可以越权获取管理员账号密码 漏洞复现 FOFA title"锐捷网络 --NBR路由器--登录界面" 请求包 POST /WEB_VMS/LEVEL15/ HTTP/1.1 Host: Connection: keep-alive Content-Length: 73 Autho…

Python爬虫之requests模块(一)

Python爬虫之requests模块&#xff08;一&#xff09; 学完urllib之后对爬虫应该有一定的了解了&#xff0c;随后就来学习鼎鼎有名的requests模块吧。 一、requests简介。 1、什么是request模块&#xff1f; requests其实就是py原生的一个基于网络请求的模块&#xff0c;模拟…

封装左侧抽屉可拖拽组件【可多个】

一、案例效果 二、案例代码 封装抽屉组件 <template><div class"drag-drawer"><div class"out-box" :style"style"><mtd-tooltip:content"collapse ? 展开面板 : 收起面板"class"tool-tip":placeme…

AI周报(9.22-9.28)

AI应用-Siipet宠物沟通师 Siipet是一款由SiiPet公司推出的创新宠物行为分析相机&#xff0c;旨在通过尖端技术加深宠物与主人之间的情感联系。这款相机利用先进的AI算法&#xff0c;能够自动识别和分析家中宠物的行为&#xff0c;并提供定制化的护理建议。 SiiPet相机的核心功…

GUI-Guider LVGL 添加自定义代码

添加自定义代码时&#xff0c;分为上线两端 1.上部分可有可无 2.下部分为你触发事件时调用的语句 具体集合下方图片 示例参考

Python入门:掌握inspect模块,轻松调试你的代码!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 什么是inspect模块?📝 inspect模块的常用方法📝 1. 获取对象的信息📝 2. 获取函数的参数📝 3. 检查对象类型📝 4. 获取文档字符串📝 5. 获取调用方法的名称📝 实际应用场景⚓️ 相关链接 ⚓️…

[大语言模型-论文精读] Diffusion Model技术-通过时间和空间组合扩散模型生成复杂的3D人物动作

​​​​​​Generation of Complex 3D Human Motion by Temporal and Spatial Composition of Diffusion Models L Mandelli, S Berretti - arXiv preprint arXiv:2409.11920, 2024 通过时间和空间组合扩散模型生成复杂的3D人物动作 摘要 本文提出了一种新的方法&#xff0…

Spring AOP - 注解方式实现

前文已经讨论了基于配置文件方式实现Spring AOP&#xff08;Spring AOP - 配置文件方式实现&#xff09;&#xff0c;本文采用注解的方式实现前文相同的功能。配置步骤如下&#xff1a; 1、项目增加aop依赖&#xff08;pom.xml) <dependency><groupId>org.springfr…

linux 安装 tomcat9、java环境

一、安装 Java环境 1. 下载文件 https://repo.huaweicloud.com/java/jdk/ 或者网盘&#xff1a;通过网盘分享的文件&#xff1a;jdk-8u192-linux-x64.tar.gz 链接: https://pan.baidu.com/s/1V3pQWzgSLJxdrUdmmKueRA 提取码: qspw 2. 查看Linux系统是否有自带的jdk&#xf…

代码随想录_刷题记录_第四次

二叉树 — 理论基础 种类&#xff1a; 满二叉树&#xff08;所有层的节点都是满的&#xff0c;k&#xff1a;深度 节点数量&#xff1a;2^k - 1&#xff09;完全二叉树&#xff08;除了最后一层&#xff0c;其余层全满&#xff0c;并且最后一层从左到右连续&#xff09;二叉搜…

C语言扫盲

文章目录 C版本C语言特征GCCprintf数据类型函数指针内存管理void指针 Struct结构和Union结构typedef预处理器make工具cmake工具Projectintegral of sinc functionemulator embedded systeman event schedule 补充在线Linux终端安装Linux参考 建议还是国外教材学习…人家的PPT比…

【ESP32】Arduino开发 | I2C控制器+I2C主从收发例程

有关I2C控制器的详细介绍放在了IDF开发的文章中&#xff0c;跳转栏目目录可以找到对应的文章。 1. API Arduino启动时就已经实例化了两个I2C设备类&#xff0c;分别对应Wire和Wire1对象。 1.1 初始化 bool begin(int sda, int scl, uint32_t frequency0); // returns true, i…

【2023工业3D异常检测文献】PointCore: 基于局部-全局特征的高效无监督点云异常检测器

PointCore: Efficient Unsupervised Point Cloud Anomaly Detector Using Local-Global Features 1、Background 当前的点云异常检测器可以分为两类&#xff1a; &#xff08;1&#xff09;基于重建的方法&#xff0c;通过自动编码器重建输入点云数据&#xff0c;并通过比较原…

召回09 双塔模型+自监督学习

引入&#xff1a; 自监督学习改进双塔模型&#xff0c;可以提升业务指标。自监督学习是把物品塔学习得更习的更好。 长尾物品的曝光和点击数量太少&#xff0c;训练的样本次数不够。自监督可以更好地学习长尾数据的物品表征。 双塔模型的训练&#xff1a; 线上召回的时候不用纠…

【tbNick专享】虚拟机域控、成员服务器、降级等管理

在 VMware 中完成四台域控服务器、一台成员服务器的创建、降级域控为成员服务器&#xff0c;并创建子域的操作。 1. 创建四台域控和一台成员服务器 1.1 在 VMware 中创建虚拟机 启动 VMware Workstation&#xff1a; 打开 VMware Workstation&#xff0c;点击 “创建新的虚拟…

AIGC学习笔记—minimind详解+训练+推理

前言 这个开源项目是带我的一个导师&#xff0c;推荐我看的&#xff0c;记录一下整个过程&#xff0c;总结一下收获。这个项目的slogan是“大道至简”&#xff0c;确实很简。作者说是这个项目为了帮助初学者快速入门大语言模型&#xff08;LLM&#xff09;&#xff0c;通过从零…

十分钟实现内网连接,配置frp

十分钟实现内网连接&#xff0c;配置frp 一.frp是什么&#xff1f;其实是一款实现外网连接内网的一个工具&#xff0c;个人理解&#xff0c;说白了就像是teamviwer一样&#xff0c;外网能访问内网。 利用处于内网或防火墙后的机器&#xff0c;对外网环境提供 http 或 https 服…

CSS04-Chrome调试工具

Chrome 浏览器提供了一个非常好用的调试工具&#xff0c;可以用来调试我们的 HTML结构和 CSS 样式。

Redis实战(使用Scan,Lua脚本,一次扣多个库存,多线程并发使用,并发获取分布式锁,BItMap实现签到和在线统计)

1.使用Scan 2.lua脚本操作Redis 一次扣减一个商品库存 一次扣减多个商品的库存 Testvoid test100() {String key "product.1";stringRedisTemplate.opsForValue().set("product.1","10");stringRedisTemplate.opsForValue().set("produc…