协议栈——收发数据(拼接网络包,自动重发,滑动窗口机制)
目录
协议栈何时发送数据~
数据长度
IP模块的分片功能
发送频率
网络包序号~利用syn拼接网络包ack确认网络包完整
确定偏移量
服务器ack确定收到数据总长度
序号作用
双端告知各自序号
协议栈自动重发机制
大致流程
ack等待时间如何调整
是否需要等待收到ack号后在发送数据~滑动窗口
合并ack号和窗口大小
总结
1.发送方协议栈根据DNS提供的服务器ip端口确定和服务器通信使用的socket套接字, 填充tcp头部信息(发送接受方ip端口信息),将syn设置为1,修改当前socket状态为正在连接
2.发送方委托ip模块发送给服务器的ip模块。服务器的ip模块再给到服务器的tcp模块,根据头部信息找到发送发要连接的socket并填入对应的客户端ip端口,接着创建tcp头部信息(发送和接收方ip端口)此时的发送方是服务器,并填充syn报文值为1(代表链接成功)和一个ack等于1的报文(代表网络包和序号都收到)委托服务器ip模块发送(建立连接的确认过程文末讲解)
3.客户端收到后完善socket中的服务端ip地址端口信息,判断服务端返回的syn是否为1来确定是否链接成功 接着设置socket状态为连接完毕;最后 向服务端模块在发送一个ack报文1确认网络包收到(tcp头部信息还是必须要填写的)
协议栈何时发送数据~
建立连接后应用就可以和服务端进行通信了,应用发的数据会缓存到协议栈中,但是何时发送呢?有两种情况,下面介绍
数据长度
应用可以指定发送数据的大小,如果协议栈收到发送指令就进行发送的话,不可控而且效率低;因此协议栈内部会指定一个长度,当达到长度后在进行发送,此前发送的数据保存到缓冲区中。
这个长度就是mtu(包含了tcp,ip头部控制信息);除去网络包的头部信息后叫做真实数据的最大传输单元,叫做mss。
MTU:Maximum Transmission Unit,最大传输单元
头部信息是固定长度,MTU长度又是固定的,因此mss可知。
图中列出的是TCP头部,同理UDP也是一样将TCP头部换为UDP头部也一样
MTU:以太网中传输的一个网络包的最大数据长度,一般为1500字节。
MSS:除去TCP/UDP模块的头部控制信息之后,一个网络包所能容纳的数据的最大长度。

报头,起始分界符,FCS是协议栈下层的网卡模块添加的,网卡模块介绍。
IP模块的分片功能

我们来回顾下,协议栈的TCP和UDP模块填充各自模块的头部控制信息后,交给IP模块去发送数据,最后一层是IP模块,因此IP模块发送的数据长度也就是协议栈发出的数据长度。
TCP/UDP模块发送的数据肯定超过了以太网和通信线路的最大传输长度也就是MTU,这个时候IP模块就会对来自TCP/UDP模块的数据进行分片,在这篇文章中的分片重组进行了介绍。
接下来举个例子看下UDP模块可以发送的最大数据长度和协议栈最终发出去的数据长度(也即IP模块发出去的数据长度) 是如何变化的(TCP也一样):
UDP模块可发送的最大传输数据长度是IP包的最大长度减去IP头部和UDP头部。IP包的最大长度为16比特(2的16次方-1)也就是65535字节,不考虑其他可选字段的话 IP头部最大长度为20字节,UDP头部是8字节,也就是UDP可传输最大长度为65507字节,超过了协议栈所规定的最大传输长度MTU 1500字节,因此需要使用IP模块的分片功能进行切割。,关于切割分片和重组分片请查看上面提到的文章有详细介绍。
可以看到TCP模块和UDP模块所规定的最大数据长度和协议栈最终发出的数据长度之间经过了IP模块的分片功能处理。也很好理解,越往底层传输的数据量越小,总不能让上层传输的是0101或者数据长度特别小的数据吧(使用者也不方便),越往下每一层都进行切割最后切割到可以在网线中传输的0101信号。
发送频率
除了考虑数据长度外,还有一个因素要考虑,就是应用发送数据的频率。
应用程序发送数据的频率不高的时候,如果每次都等到长度接近MSS时再发送,可能会因为等待时间太长而造成发送延迟,这种情况下,即便缓冲区中的数据长度没有达到MSS,也应该果断发送出去。为此,协议栈的内部有一个计时器,当经过一定时间之后,就会把网络包发送出去。
大致流程:
因此上层应用程序发送的数据会放到协议栈的缓冲区中,当满足上面两个因素条件之一时(应用程序也可以指定是否立即发送数据还是按照协议栈的规则判断时机)就可以发送数据了,首先切割mss为单位的数据块,在每个数据库开头都加上头部控制信息:
拆分示意图:协议栈的TCP模块负责添加tcp头部信息,接着委托协议栈的ip模块检查是否需要切片然后发送消息,ip模块会再分片后的包中添加ip头部和mac头部信息

网络包序号~利用syn拼接网络包ack确认网络包完整
上面说过网络包会拆分,那么服务器是怎么知道该怎么拼接这些网络包还原成最初的数据呢?答案是通过序号
确定偏移量
当拆分数据拼接成网络包的时候,会将这块数据相对于起始数据的偏移字节算出来携带到tcp头部;除此之外还会携带数据包的总长度
网络包的数据长度不是放到tcp头部中, 因为用整个网络包的长度(固定的mss)减去头部的长度就可以得到数据的长度,所以接收方可以用这种方法来进行计算。有了上面两个数值,我们就可以知道发送的数据是从第几个字节开始,长度是多少了。
服务器ack确定收到数据总长度
接收方会将到目前为止接收到的数据长度加起来,计算出一共已经收到了多少个字节,然后将这个数值写入TCP头部的ACK号中发送给发送方。
序号作用
序号的作用:上面的偏移量是携带到tcp头部中,很容易就会拿到自行还原数据破解的;因此在传递过程中每个包的数据长度都要进行基于某个值偏移,也就是将原来的偏移量要加上序号。
如第一个包默认的偏移量本来是0,序号值是666,那么现在添加序号之后第一个网络包的偏移量就是666
这样对方就搞不清楚偏移量到底是从多少开始计算的。
实现这种方式需要在开始收发数据之前将初始值告知通信对象。同样服务端也需要告知序号值这样客户端就知道该如何拆分。这个偏移量就是序号值
双端告知各自序号
那么什么时候把这个初始序号值发送给对方呢?
在发送连接的阶段中会将syn设置为1, 在将SYN设为1的同时,还需要同时设置序号字段的值,而这里的值就代表序号的初始值。这个syn就是通过告知序号值用于后面通信步调一致(知道每个网络包头部的偏移量是基于序号值+当前网络包相对于数据头部的偏移量),同样第二个阶段服务器返回syn1也是告知客户端之后发送包的序号值;同时发送ack数值告知客户端数据是否发送完整(需要利用客户端传过来的序号值,偏移量减去序号就是真正的偏移量了);客户端收到后同样也需要向服务端发送ack来确认服务端发过来的数据是否完整(服务端发送syn1的时候将服务端的序号也发送了过来,也是用的这个序号来拼接服务端发送过来的数据)
这个就是大致的网络包拼接流程:


协议栈自动重发机制
自动重发机制:协议栈会在收到ack号确认之前中会存放发送的数据,如果某一个ack号没有发送过来就会重发这个数据。
大致流程
这样一来,无论网络中发生任何错误,协议栈都可以发现并采取补救措施(重传网络包) 。反过来说,有了这一机制,就不需要在其他地方对错误进行补救了。
因此,网卡、集线器、路由器都没有错误补偿机制,一旦检测到错误就直接丢弃相应的包。应用程序也是一样,因为采用TCP传输,即便发生一些错误对方最终也能够收到正确的数据,所以应用程序只管自顾自地发送这些数据就好了。不过,如果发生网络中断、服务器宕机等问题,那么无论TCP怎样重传都不管用。这种情况下,无论如何尝试都是徒劳,因此TCP会在尝试几次重传无效之后强制结束通信,并向应用程序报错
ack等待时间如何调整
ack等待时间也叫超时时间,如果协议栈发送数据等待ack的返回这段时间超过了超时时间,就会重新发送这个网络包。
但是网络信号是可以改变的,所以超时时间也应该和网络信号的好坏动态调整;并且网络信号差的时候不仅仅只是重发一个包这么简单后面的所有网络包都会收到影响(这个和安卓的anr排查差不多)
这个等待时间是根据ACK号返回所需的时间来判断的。具体来说,TCP会在发送数据的过程中持续测量ACK号的返回时间,如果ACK号返回变慢,则相应延长等待时间;相对地,如果ACK号马上就能返回,则相应缩短等待时间。
是否需要等待收到ack号后在发送数据~滑动窗口
现在的链路是 客户端服务端确认好端口ip后就开始通信了,客户端每次发送数据包携带数据长度信息 服务端返回ack信息确认是否完整收到(反过来也是一样的流程)
但是有个缺点 就是接收方必须等到发送方返回ack才能继续传输这会增加延时降低通信效率
所以采用滑动窗口的方式。客户端只管发送 不管是否收到ack报文 。
所谓滑动窗口,就是在发送一个包之后,不等待ACK号返回,而是直接发送后续的一系列包。这样一来,等待ACK号的这段时间就被有效利用起来了。


这样虽说提高了效率但是如果不等返回ACK号就连续发送包, 服务端的处理缓冲区会造成背压问题 (发送包的频率超过接收方处理能力的情况)。
发送的数据会存储在接收方的缓冲区中,之后取出来处理拼接ack号,如果什么都不管一直发送,缓冲区的数据会溢出,某些数据就会被放弃,这个肯定不是想要的结果。因此需要出一种机制能够知道对方缓冲区可以接受多少数据,根据这个值来判断是否继续发送,当服务器的缓冲区数据处理后,也需要告知客户端(通过tcp头部中的窗口字段)
图示:

合并ack号和窗口大小
如果接收方可以告知发送方当前可以容纳多少数据呢?发送方自己判断已发送的数据是不是到达极限从而暂停 当接收方处理数据时再通知客户端当前缓冲区容纳数据客户端在发送,这样是不是完美了?
并不是,如何确定ack和发送缓冲区数量的包呢?是分开发送吗还是合并 如果每次都携带缓冲区数量是不必要的 发送方知道后自己就可以判断是否达到缓冲区处理极限决定是否发送之后数据,那分开呢?又会降低效率 增加包的数量无疑会导致延迟效率下降
因此 这两个得合并但是不能每次都发,所以加了个延时的操作。
分为以下这几种情况
- 假如我等待发送ack数据时正好服务器处理了数据缓冲区容量更新需要通知到客户端这时候合并 就可以了。
- 再比如我处理完数据了 等待一段时间如果ack也要发送也用合并发送
- 并且如果需要连续发送缓冲区的数量时说明处理速度很快只要同步最后一次的缓冲区可用数量即可(比如200---400--600)等待一段时间发生减少包数量
- 需要连续发送ack时也是一样 说明客户端连续发送数据 接收方这边等待一段时间之后直接把刚收到的数据总和返回给客户端就行
通过延时解决合并不必要和独立数量多的缺点 具体延时根据实际情况判断(很多时候服务器处理速度很快几乎发送完数据就能立马处理完不需要缓冲区数量这个信息)
总结
协议栈会检查收到的数据块和TCP头部的内容,判断是否有数据丢失,如果没有问题则返回ACK号。然后,协议栈将数据块暂存到接收缓冲区中,并将数据块按顺序连接起来还原出原始的数据,最后将数据交给应用程序。具体来说,协议栈会将接收到的数据复制到应用程序指定的内存地址中,然后将控制流程交回应用程序。将数据交给应用程序之后,协议栈还需要找到合适的时机向发送方发送窗口更新。
原文链接:协议栈——收发数据(拼接网络包,自动重发,滑动窗口机制) - 掘金 (juejin.cn)
相关文章:
协议栈——收发数据(拼接网络包,自动重发,滑动窗口机制)
目录 协议栈何时发送数据~ 数据长度 IP模块的分片功能 发送频率 网络包序号~利用syn拼接网络包ack确认网络包完整 确定偏移量 服务器ack确定收到数据总长度 序号作用 双端告知各自序号 协议栈自动重发机制 大致流程 ack等待时间如何调整 是…...
传输层协议——TCP、UDP
目录 1、UDP 协议(用户数据报协议) 协议特点 报文首部格式 2、TCP 协议(传输控制协议) 协议特点 报文首部格式 TCP连接建立时的三次握手 TCP拆除连接的四次挥手 TCP的流量控制 TCP的拥塞控制 3、传输层端口号 三类端口…...
优化您的Spring应用程序:缓存注解的精要指南
优化您的Spring应用程序:缓存注解的精要指南 前言详细说明1. Cacheable:2. CacheEvict:3. CachePut:4. Caching:5. CacheConfig: 项目中的实现前提使用 前言 当我们构建和运行Spring应用程序时,…...
Java之原子性问题的解决
2. 原子性 2.1 volatile-问题 代码分析 : package com.itheima.myvolatile; public class Demo {public static void main(String[] args) {MyThread1 t1 new MyThread1();t1.setName("小路同学");t1.start(); MyThread2 t2 new MyThread2();t2.setName(&q…...
实时目标检测:基于YOLOv3和OpenCV的摄像头应用
一、前言 随着人工智能和计算机视觉技术的不断发展,目标检测成为了智能监控、自动驾驶、机器人等领域的关键技术之一。实时目标检测更是对系统的反应速度和准确度提出了更高的要求。本文介绍使用OpenCV和YOLOv3实现实时目标检测的方法,演示如何使用OpenCV调用YOLOv3模型进行…...
【软考】4.2 关系代数
《 关系代数 》 表和表之间的逻辑运算 笛卡尔积:S1 x S2 投影:π;选择某一列(属性);一个关系R的投影操作结果也是一个关系,记作Πa,它由从关系R中选出的A列元素构成;选择…...
STM32F4学习笔记读取芯片UID和MAC地址
一、简介 在嵌入式设备开发过程中有时会需要为设备设置唯一的ID用以标识设备唯一,比如要求同一总线上的所有设备ID不能重复,要求设备具体唯一的MAC地址等等。每个STM32微控制器都自带一个96位的唯一ID,这个ID在任何情况下都是唯一且不允许修…...
webpack优化策略
这三点是webpack优化策略的一部分,具体解释如下: 优化正则匹配(Test):在webpack的配置中,test属性是一个正则表达式,用于匹配需要应用该loader的文件的扩展名。在您提供的代码中,te…...
讲讲项目里的仪表盘编辑器(三)布局组件
布局容器处理 看完前面两章的讲解,我们对仪表盘系统有了一个大概的理解。接着我们讲讲更深入的应用。 上文讲解的编辑器只是局限于平铺的组件集。而在编辑器中,还会有一种组件是布局容器。它允许其他组件拖拽进入在里面形成自己的一套布局。典型的有分页…...
Linux- 后台运行符、nohup、disown
& &在Unix-like的操作系统(如Linux和macOS)的shell中,特别是在Bash这样的shell中,经常用作后台运行符号。让我们深入了解一下其功能和用法。 &作为后台运行符号: 基本用法: 当我们在一个命令或者一组命令…...
开发过程教学——交友小程序
交友小程序 1. 我的基本信息2. 我的人脉2.1 我的关注2.2 我的粉丝 3. 我的视频4. 我的相册 特别注意:由于小程序分包限制2M以内,所以要注意图片和视频的处理。 1. 我的基本信息 数据库表: 我的基本信息我的登录退出记录我的登录状态&#x…...
正则表达式 Regular Expression学习
该文章内容为以下视频的学习笔记: 10分钟快速掌握正则表达式_哔哩哔哩_bilibili正则表达式在线测试工具:https://regex101.com/, 视频播放量 441829、弹幕量 1076、点赞数 19330、投硬币枚数 13662、收藏人数 26242、转发人数 2768, 视频作者 奇乐编程学…...
代谢组学最常用到的数据分析方法(五)
代谢组学是一门对某一生物或细胞所有低分子质量代谢产物(以相对分子质量<1000的有机和无机的代谢物为研究核心区)进行分析的新兴学科。因此从复杂的代谢组学数据中确定与所研究的现象有关的代谢物,筛选出候选生物标记物成为代谢物组学研究…...
105.从前序与中序遍历序列构造二叉树
力扣题目链接(opens new window) 根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder [3,9,20,15,7] 中序遍历 inorder [9,3,15,20,7] 返回如下的二叉树: class Solution { public:Tr…...
分支定界、分支切割、分支定价的区别
目录 1.从原理的角度 (1)分支定界: (2)分支切割: (3)分支定价: 2.从分支树的角度 (1)分支定界 (2)分支切割 &…...
数字IC前端学习笔记:数字乘法器的优化设计(阵列乘法器)
相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 数字信号处理作为微处理器的核心部件,是决定着总体处理器性能的因素之一,而数字乘法器是最常见的一种数字信号处理电路。通常情况下&#…...
批量删除wordpress文章修订版本/自动草稿残留数据(3种方法)及四种方法禁用WordPress文章历史修订/自动保存/自动草稿功能
目录 1、批量删除wordpress文章修订版本/自动草稿残留数据(3种方法) 方法一:SQL命令批量删除 命令: 方法二:利用PHP代码来删除 方法三:利用数据库清理优化插件 WP Clean Up 或 WP Cleaner 批量删除 2…...
HTTP初识,fiddler的使用,URL各部分介绍,QueryString
目录 一、什么是HTTP 二、抓包工具 三、请求的首行 URL 四、URL的各部分详细介绍 一、什么是HTTP 现在网页上,我们常见的是https,但是在二十年前是以http为主,这个协议也叫超文本传输协议,文本->字符串,“超文本”->图片…...
计算机毕业设计 基于SpringBoot的图书馆管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...
第三章:最新版零基础学习 PYTHON 教程(第十二节 - Python 运算符—Python 中的运算符函数 - 套装1)
Python 在“operator”模块下预定义了许多数学、逻辑、关系、位等运算的函数。本文介绍了一些基本功能。 1. add(a, b):- 该函数返回给定参数的加法。 操作-a +b。 2. sub(a, b):- 该函数返回给定参数的差值。 操作-a -b。 3. mul(a, b):- 该函数返回给定参数的乘积。 操…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
