协议栈——收发数据(拼接网络包,自动重发,滑动窗口机制)

目录

协议栈何时发送数据~

数据长度

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模块的分片功能

image.png

我们来回顾下,协议栈的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)

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

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

相关文章

java做个qq机器人

前置的条件 机器人是基于mirai框架实现的。根据官方的文档&#xff0c;建议使用openjdk11。 我这里使用的编辑工具是idea2023 在idea中新建一个maven项目&#xff0c;虽然可以使用gradle进行构建&#xff0c;不过我这里由于网络问题没有跑通。 pom.xml <dependency>&l…

2023年CSP-J真题详解+分析数据

目录 亲身体验 江苏卷 选择题 阅读程序题 阅读程序(1&#xff09; 判断题 单选题 阅读程序(2) 判断题 单选题 阅读程序(3) 判断题 单选题 完善程序题 完善程序(1) 完善程序(2) 2023CSP-J江苏卷详解 小结 亲身体验 2023年的CSP-J是在9月16日9:30--11:30进行…

竞赛选题 深度学习 opencv python 公式识别(图像识别 机器视觉)

文章目录 0 前言1 课题说明2 效果展示3 具体实现4 关键代码实现5 算法综合效果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的数学公式识别算法实现 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学…

【实用工具】谷歌浏览器插件开发指南

谷歌浏览器插件开发指南涉及以下几个方面&#xff1a; 1. 开发环境准备&#xff1a;首先需要安装Chrome浏览器和开发者工具。进入Chrome应用商店&#xff0c;搜索“Extensions Reloader”和“Manifest Viewer”两个插件进行安装&#xff0c;这两个插件可以方便开发和调试。 2…

Win11 安装 Vim

安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Ru7HhTSotz9mteHug-Yhpw?pwd6666 提取码&#xff1a;6666 双击安装包&#xff0c;一直下一步。 配置环境变量&#xff1a; 先配置系统变量中的path&#xff1a; 接着配置用户变量&#xff1a; 在 cmd 中输入…

图的广度遍历-邻接矩阵实现

description 本题要求实现邻接矩阵存储图的广度优先遍历。 函数接口定义&#xff1a; void BFS(MGraph G,Vertex i); 其中MGraph是邻接矩阵存储的图&#xff0c;定义如下&#xff1a; #define MaxVertexNum 10 /定义最大顶点数/ typedef int Vertex;/* 用顶点下标表示顶点,…

这可能是最全的反爬虫及应对方案,再也不怕爬不到数据了

一、什么是反爬虫 网络爬虫&#xff0c;是一个自动提取网页的程序&#xff0c;它为搜索引擎从万维网上下载网页&#xff0c;是搜索引擎的重要组成。但是当网络爬虫被滥用后&#xff0c;互联网上就出现太多同质的东西&#xff0c;原创得不到保护。于是&#xff0c;很多网站开始…

Java项目:高仿12306

github地址&#xff1a;nageoffer/12306: &#x1f525; 官方推荐 &#x1f525; 大学春招、秋招、应届项目&#xff0c;SpringBoot3 Java17 SpringCloud Alibaba Vue3 等技术架构&#xff0c;完成高仿铁路 12306 用户 抢票 订单 支付服务&#xff0c;帮助学生主打就业的…

网站强制跳转至国家反诈中心该怎么办?怎么处理?如何解封?

在互联网环境中&#xff0c;网站安全是非常重要的。然而&#xff0c;在实际操作过程中&#xff0c;不少网站可能因内容问题、技术安全漏洞等原因被迫下线甚至跳转至国家反诈骗中心网址。面对这一严峻问题&#xff0c;我们如何有效解决&#xff0c;让网站恢复运行并解除强制跳转…

在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 示例 1&#xff1a…

解决前端二进制流下载的文件(例如:excel)打不开的问题

1. 现在后端请求数据后&#xff0c;返回了一个二进制的数据&#xff0c;我们要把它下载下来。 这是响应的数据&#xff1a; 2. 这是调用接口的地方&#xff1a; uploadOk(){if(this.files.length 0){return this.$Message.warning("请选择上传文件&#xff01;&#xff…

Multi Label Classification with Missing Labels(MLML)的几种loss设计

多标签学习这个方向问题比较多&#xff0c;可以参考多标签学习的新趋势&#xff08;2021 Survey TPAMI&#xff09; 和 部分标签学习和缺失标签学习到底什么异同&#xff1f; 这两篇偏综述性质的解释。本文重点解释下面几个重点问题&#xff1a; Multi Label Classification w…

第十五章 类和对象——友元

生活中你的家有客厅(Public)&#xff0c;有你的卧室(Private) 客厅所有来的客人都可以进去&#xff0c;但是你的卧室是私有的&#xff0c;也就是说只有你能进去 但是呢&#xff0c;你也可以允许你的好闺蜜好基友进去。 在程序里&#xff0c;有些私有属性 也想让类外特殊的一些…

【物联网】STM32的中断机制不清楚?看这篇文章就足够了

在嵌入式系统中&#xff0c;中断是一种重要的机制&#xff0c;用于处理来自外部设备的异步事件。STM32系列微控制器提供了强大的中断控制器&#xff0c;可以方便地处理各种外部中断和内部中断。本文将详细介绍STM32中断的结构和使用方法。 文章目录 1. 什么叫中断2. 中断优先级…

Jmeter基础篇

1.性能测试指标 【虚拟用户数】&#xff1a;线程用户 【并发数】&#xff1a;指在某一时间&#xff0c;一定数量的虚拟用户同时对系统的某个功能进行交互&#xff0c;一般通过集合点实现 【事务】:事务代表一个完整的功能&#xff0c;一个接口可以是事务&#xff0c;多个接口…

linux——进程间通信——管道

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;Linux——进程间通信——管道通信 ☂️<3>开发环境&#xff1a;Centos7 &#x1f4ac;<4>前言&#xff1a;进程间通信&#xff08;InterProcess Communication&…

Matlab杂项记录

文章目录 其他do nothing command in matlab代码格式化在同一个m文件中写多个独立的功能函数改变启动时的默认文件夹博文链接 table使用 其他 do nothing command in matlab disp() % Does nothing but allows developer to set a breakpoint here.代码格式化 Matlab编辑器具…

Python的函数

近期遇到了一个没怎么看懂的Python函数的形式。 def twoSum(self, nums: List[int], target: int) -> List[int]: 后来上网查了资料。

(二)激光线扫描-相机标定

1. 何为相机标定? 当相机拍摄照片时,我们看到的图像通常与我们实际看到的不完全相同。这是由相机镜头引起的,而且发生的频率比我们想象的要高。 这种图像的改变就是我们所说的畸变。一般来说,畸变是指直线在图像中出现弯曲或弯曲。 这种畸变我们可以通过相机标定来进行解…

阿里云服务器地域和可用区查询表_地域可用区大全

阿里云服务器地域和可用区有哪些&#xff1f;阿里云服务器地域节点遍布全球29个地域、88个可用区&#xff0c;包括中国大陆、中国香港、日本、美国、新加坡、孟买、泰国、首尔、迪拜等地域&#xff0c;同一个地域下有多个可用区可以选择&#xff0c;阿里云服务器网分享2023新版…