第三十一篇:TCP协议如何解决丢包的问题,TCP系列六

前面我们说TCP协议是可靠的、基于字节流、面向连接的传输层通信协议

这里我想换种说法:与其说是TCP协议是可靠的,不如说传输层程序软件实现了TCP协议的规范(网络层次模型,每一层都有对应的程序软件),让TCP协议是可靠的

1、数据分片(拆包

如果传输的数据过小,例如数据只有1byte,那么为了传输这1byte数据,至少要消耗20字节IP头部+20字节TCP头部=40byte,这还不包括其二层头部所需要的开销,显然这种数据传输效率是很低的。

如果传输的数据过大,导致数据包很大,那么在IP传输中被分片的可能性会很大,接收方在处理分片包所消耗的资源和处理时间都会增大,同时如果IP分片在传输中发生了丢失,因为IP网络层没有重传机制,导致接收方接收不到完整数据,而要求发送方整个数据都重传,那么其网络开销也会增大。

所以传输层传输的数据不能过大也不能过小,最理想的状况是最大消息长度正好是IP不会被分片处理的最大长度;我们把这样一个合理的数据传输范围,叫做“最大消息长度”(MSS:Maximum Segment Size)。

那么这个数据传输范围是怎么进行确认的呢?

①② 通过建立连接的SYN包相互通知对方网络接口的MSS值。

③ 在两者之间选一个较小的作为MSS的值,发送数据。

上面通过TCP三次握手,选择了两端MSS较小的那个作为传输大小。如果发送的数据大于这个值,则会根据这个MSS值对数据进行分片,分片发送给接收端。

TCP层数据可能会进行分片,那如果某分片的数据中途丢失,那么数据在对端就无法还原了,面对这种情况,那么TCP协议又是如何规范的,如何保证主机一定收到对端的数据的呢?

2、到达确认

接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认发送端接收到确认信息才认为成功

3、报文重传

发送方发送的某个报文如果长时间没有收到接收方的确认应答则这个报文将会被重发

重传方式有超时重发快速重发SACK方法Duplicate SACK)。

1)超时重发

发送方在发送分片时设置超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片数据。超时传时间是以 RTO (Retransmission Timeout 超时传时间)表示。

情况一数据包丢失

情况二:确认应答丢失

这种情况客户端会继续重复发送未被应答的报文,服务端接收到之后,会判断有没有曾经接收到,如果已存在,就丢弃新发来的包,然后返回确认应答报文。

服务端给客户端发送信息也是一样的逻辑

那定时器是如何确定超时时间的呢

在了解定时器是如何确定超时传时间(RTO)之前,先了解一个概念:

往返时延(RTT:Round-Trip Time):表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。

那我们的超时重传时间(RTO)定多少合适呢?有人可能会说,让超时重传时间(RTO)稍大于包的往返时间(RTT)就可以了;听起来没错,但是网络是复杂的,每次包的往返时间可能都不一样,有的因为网络拥塞,花费时间比较长,有的则比较短;如果设置的过长,则如下所示:

  • 当超时时间 RTO 较⼤时,发慢,包丢了⽼半天才发,没有效率,性能差,同时影响用户体验

如果过短,则会如图所示:

  • 当超时时间 RTO 较⼩时,会导致包可能并没有丢就被重发,这会增加⽹络拥塞,导致更多的超时,更多的超时导致更多的重发。
  • 根据上述的两种情况,我们可以得知,超时重传时间 RTO 的值应该略⼤于报⽂往返 RTT 的值。

每发送一个分组,TCP都会进行RTT采样,这个采样并不会每一个数据包都采样,同一时刻发送的数据包中,只会针对一个数据包采样,这个采样数据被记为sampleRTT,用它来代表所有的RTT。

采样的方法一般有两种:

  • TCP Timestamp选项在TCP头部的选项里面

TCP时间戳选项可以用来精确的测量RTT。

RTT = 当前时间 - 数据包中Timestamp选项的回显时间

这个回显时间是该数据包发出去的时间,知道了数据包的接收时间(当前时间)和发送时间

(回显时间),就可以轻松的得到RTT的一个测量值。这个方法简单并且准确,但是需要发送段和接收端都支持这个选项。

  • 重传队列中数据包的TCP控制块

每个数据包第一次发送出去后都会放到重传队列中,数据包中的TCP控制块包含着一个变量,全连接信息里面的when,记录了该数据包的第一次发送时间。如果没有时间戳选项,那么RTT就等于当前时间和when的差值。

  • 对于重传的数据包的响应,方法1可以用它来采集一个新的RTT测量样本,而方法二则不能(因为全连接信息里面的when不会因为重发而变化)。因为TCP Timestamp选项可以区分这个响应是原始数据包还是重传数据包触发的,从而计算出准确的RTT值。

重点来了:RTO的计算

实际上「报⽂往返 RTT 的值」是经常变化的,因为我们的⽹络也是时常变化的。也就因为「报⽂往返 RTT 的值」是经常波动变化的,所以「超时传时间 RTO 的值」应该是⼀个动态变化的值。

(1)经典方法

为了避免单次RTT波动,计算RTO时新引入了变量SRTT,表示更加平滑的RTT数值,它的计算方法:

SRTT = x(上一次计算所得的SRTT) + (1 - x)RTT;

x被称为平滑因子,一般建议设置在[0.8, 0.9],意思是SRTT值百分之八十来自于之前的值,百分之二十来自于当前值。然后计算RTO的方法为:

RTO = min(ubound, max(lbound, y(SRTT)));

y是时延离散因子,推荐值为[1.3, 2.0],ubound是RTO的上边界,lbound是RTO的下边界。

算法的缺点:在RTT波动较大时,RTO不能明显适应网络变化。

(2)标准方法(Jacobson / Karels 算法)

标准方法引入了平均偏差的概念,它类似于统计学里面的方差,但是因为方差的计算过程代价较大,对于快速TCP来说不太适合。假设rtt的值为M,RTO的计算方式为:

1

srtt = (1 - g)srtt + g(M);

2

rttval = (1 - h)rttval + h(|M - rttval|);

3

RTO = srtt + 4(rttval);

其中g设置为1/8,h设置为1/4,对srtt而言,它有1/8取决于当前值,7/8取决于现有值。当RTT变化时,偏差增量越大,RTO的增量也越大。(其中:在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4 ——这就是算法中的“调得一手好参数”,nobody knows why, it just works…) 最后的这个算法在被用在今天的TCP协议中。

关于计算RTT和RTO的算法,还有很多种,历史上针对这个的探讨从未停止过。

比较出名的拥塞算法还有谷歌的bbr算法,高版本的linux内核已经合入了bbr算法作为拥塞控制算法。

如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。

也就是每当遇到⼀次超时重传的时候,都会将下⼀次超时时间间隔设为先前值的两倍。两次超时,就说明⽹络环境差,不宜频繁反复发送。

超时触发重传存在的问题是,超时周期可能相对较⻓。那是不是可以有更快的⽅式呢?

于是就可以⽤「快速重传」机制来解决超时重发的时间等待。

2)快速重发

TCP以一个段为单位(一个或多个字节组成一个段),每发一个段就进行一次应答处理,这样的传输方式由一个缺点。那就是,包的往返时间越长,网络的吞吐量越低,通信的性能就越低。所以为了解决这个问题,我们将不等待上一个包的确认应答而发送下一个包。这样,不同的包将不再串行而是可以并行,提高了网络吞吐。

快速重传(Fast Retransmit)机制就是基于后退N协议不以时间为驱动,⽽是确认信息驱动重传

快速传机制,是如何⼯作的呢?其实很简单,⼀图胜千⾔。

在上图,发送⽅发出了 12345 份数据:

  1. 第⼀份 Seq1 先送到了,于是就 Ack  2
  2. 结果 Seq2 因为某些原因没收到,Seq3 到达了,于是还是 Ack  2
  3. 后⾯的 Seq4  Seq5 都到了,但还是 Ack  2,因为 Seq2 还是没有收到;
  4. 发送端收到了三个 Ack = 2 的确认,知道了 Seq2 还没有收到,就会在定时器过期之前,重传丢失的 Seq2
  5. 最后,收到了 Seq2,此时因为 Seq3Seq4Seq5 都收到了,于是 Ack  6

所以,快速传的⼯作⽅式是当收到三个相同的 ACK 报⽂时,会在定时器过期之前,传丢失的报⽂段。

快速传机制只解决了⼀个问题,就是超时时间的问题,但是它依然⾯临着另外⼀个问题。就是重传的时候,是重传之前的⼀个,还是重传所有的问题。

⽐如对于上⾯的例⼦,是 Seq2 呢?还是 Seq2Seq3Seq4Seq5 呢?因为发送端并不清楚这连续的三个 Ack 2 是谁传回来的。

根据 TCP 不同的实现,以上两种情况都是有可能的。可⻅,这是⼀把双刃剑。

为了解决不知道该传哪些 TCP 报⽂,于是就有 SACK ⽅法。

(1)SACK方法

还有⼀种实现传机制的⽅式叫: SACK  Selective Acknowledgment 选择性确认)。

这种⽅式需要在 TCP 头部「选项」字段⾥加⼀个 SACK 的东⻄,它可以将缓存的地图发送给发送⽅,这样发送⽅就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据

如下图,发送⽅收到了三次同样的 ACK 确认报⽂,于是就会触发快速发机制,通过 SACK 信息发现只有 200~299 这段数据丢失,则发时,就只选择了这个 TCP 段进⾏复。

如果要⽀持 SACK ,必须双⽅都要⽀持。在 Linux 下,可以通过 net.ipv4.tcp_sack 参数打开这个功能(Linux 2.4 后默认打开)。

(2)Duplicate SACK方法

Duplicate SACK ⼜称 D-SACK ,其主要使⽤了 SACK 来告诉「发送⽅」有哪些数据被重复接收了。

情况1: 接收方确认报文丢包导致发送方重传

情况二网络延时导致发送包超时送达

  1. 数据包(1000~1499) 被⽹络延迟了,导致「发送⽅」没有收到 Ack 1500 的确认报⽂。
  2. ⽽后⾯报⽂到达的三个相同的 ACK 确认报⽂,就触发了快速重传机制,但是在重传后,被延迟的数据包(1000~1499)⼜到了「接收⽅」;
  3. 所以「接收⽅」回了⼀个 SACK=1000~1500,因为 ACK 已经到了 3000,所以这个 SACK 是 D-SACK,表示收到了重复的包。
  4. 这样发送⽅就知道快速重传触发的原因不是发出去的包丢了,也不是因为回应的 ACK 包丢了,⽽是因为⽹络延迟了。

可⻅, D-SACK 有这么⼏个好处:

1. 可以让「发送⽅」知道,是发出去的包丢了,还是接收⽅回应的 ACK 包丢了;

2. 可以知道是不是「发送⽅」的数据包被⽹络延迟了;

3. 可以知道⽹络中是不是把「发送⽅」的数据包给复制了;

在 Linux 下可以通过 net.ipv4.tcp_dsack 参数开启/关闭这个功能(Linux 2.4 后默认打开)。

4、利用序列号和确认应答号提高可靠性

1)重复处理

接收端接收到发送端重复发来的报文,如何判断报文已经被接收到过了呢?就是通过比对已收到报文的序列号与发来的报文序列号进行对比,确认是否存在,如存在就丢弃第二次发来的报文。

2)失序处理

作为IP数据报来传输的TCP分片到达时可能会失序,比如,把一个大报文拆分成了1、2、3个包,1、3包先到,2包后到,这个时候TCP需要将收到的数据进行重新排序,然后以正确的顺序交给应用层;重新排序的逻辑就是根据报文的序列号进行重组

3)序列号的生成逻辑

报文初始的序列号是随机生成的(在三次握手的时候),随机算法里面有一个时间的加入,所以能保证随机生成的序列与以前随机生成的不一样,如果一样可能会导致麻烦,产生数据错乱以及被黑客攻击。

序列号公式:

本次报文的序列号 = 上次报文序列号 + 上次报文携带字节数

这里我们假设客户端随机生成的序列号为X;三次握手阶段,第一次握手发送SYN报文序列为X,所以根据公式,第二次报文序列号 = X+1;上一次报文携带数据为1字节。

注:在三次握手阶段和四次挥手SYN包和FIN包等虽然不携带数据但是也会作为有一个字节的数据包

三次握手建立连接的时候,首次携带数据,序列号定位第三次握手的序列号即X+1;携带数据的字节数是1000字节:

第一次报文的序列号 = 三次握手最后的确认报文序列号 ( X + 1)。

第二次发送报文携带数据1400字节

此时该报文的序列号 = 三次握手最后的确认报文序列号 ( X + 1) + 1000= X + 1001;

第三次发送报文携带数据1200字节

此时报文序列号 = ( X + 1001) + 1400= X + 2401;

确认应答号 = 上一次对端发送过来报文里面的序列号 + 上一次对端发送过来报文携带数据的字节数表示你发的信息我收到了序列号码是XXX

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

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

相关文章

33 类与对象 · 下

目录 一、构造函数的深入 (一)构造函数的其他特点 (二)使用例 1、Date类与Time类显示写 2、Date类与Time类写一部分 (三)总结 (四)初始化顺序小题目 二、类型转化 &#xff…

【芯片设计】DC综合retiming策略的学习与实践

对于DC综合中的retiming策略早有耳闻,但是一直没有比较系统的学习和实验过,正好借着这次交付过程的归纳总结机会,把一些零零散散的收获学习记录下。 记得刚出新手村时和某位大佬聊到过,他说你逻辑里写了在某级计算一个结果&#…

UE5之5.4 第一人称示例代码阅读2 子弹发射逻辑

TP_WeaponComponent.h 看看头文件 暴露了attach weapon和fire给蓝图 这两个函数意义一看名字吧,就是捡起来枪的时候执行,一个就是发射子弹的时候执行 #pragma once#include "CoreMinimal.h" #include "Components/SkeletalMeshComponen…

Appium中的api(二)

目录 元素定位操作api 1--通过id定位api 2--通过class获取定位元素 3--通过xpath表达式定位元素 4.完整代码 解释 效果 元素定位操作api 1--通过id定位api 注:driver.find_element是获取单个元素 # 通过id获取 mySearchId "com.android.settings:id/search_acti…

如何对pdf文件进行加密?pdf文件加密全攻略与深度解析(5个方法)

如何对pdf文件进行加密? 只见,在深夜的情报局里,特工小李将一份绝密PDF文件放在保险箱内,以为这样就天衣无缝了。 细细推敲,漏洞百出: 如果钥匙被盗呢?如果被神匠破解出密码呢?如果…

Halcon基础-瓶盖带角度的OCR批量识别

Halcon基础-OCR识别 1、OCR识别素材2、创建路径文件3、Halcon代码实现4、运行效果5、资源获取 1、OCR识别素材 这里我准备了7张不同角度的OCR图片,如下所示: 2、创建路径文件 按照下图所示创建全部文件夹和文件: 01用来存放OCR识别原图 c…

Vue中使用el-upload实现文件上传时控制提交按钮状态的最佳实践

在Web应用开发中,文件上传是一个常见的需求。在使用Vue框架和Element UI库时,我们经常使用el-upload组件来处理文件上传。但是,如何在上传过程中控制提交按钮的可用状态,以避免在上传未完成时误触提交操作,是一个值得探…

解决:如何在opencv中得到与matlab立体标定一样的矫正图?(python版opencv)

目的:采用一样的标定参数,matlab中和opencv中的立体矫正图像是一样的吗?不一样的话怎么让它们一样? 结论:不一样。后文为解决方案。 原因:注意matlab的标定结果在matlab中的用法和在opencv中的用法不一样&a…

光伏电站折旧率的计算

折旧率的计算方法 直线法:直线法是最常用的折旧计算方法。它假设光伏设备在使用寿命内每年的折旧额保持不变。计算公式为: 折旧率(资产原值-净残值)预计使用寿命。 其中,资产原值是指光伏设备购置价值或建成投产时的价值;净残值…

chrome清除https状态

莫名其妙的http跳转到https的url了。 解决办法 浏览器地址栏输入:chrome://net-internals/#hsts 输入你需要删除的域名即可!!!

AMD平台,5600X+6650XT,虚拟机安装macOS 15 Sequoia 15.0.1 (2024.10)

macOS 15 Sequoia终于出正式版了,没有Mac,所以还是虚拟机玩玩,还是属于折腾,安装过程和之前差不多,这次我从外网获得了8核和16核openCore,分享一下。 提前发一下ISO镜像地址和openCore引导磁盘地址 ISO镜…

《人工智能往事》—— 简而言之,AI 已经包围了我们。AI 就是我们。

《人工智能往事》这本书我挺喜欢的(推荐给对计算机和AI史有考古兴趣的同学们)。我是几年前读的英文版《This Could Be Important: My Life and Times with the Artificial Intelligentsia Pamela McCorduck》很高兴发现国内推出了译本。 作者帕梅拉麦考…

一座数智工厂,看见汽车制造的诗与远方

今天的中国,已经是名副其实的汽车制造与出口大国。 根据国家统计局10月18日发布的数据,今年9月中国新能源汽车产量同比增长48.5%,增速为2023年5月以来新高。1月至9月汽车行业出口交货值同比增长17.1%。中国汽车产业的高速发展,离不…

学习docker第三弹------Docker镜像以及推送拉取镜像到阿里云公有仓库和私有仓库

docker目录 1 Docker镜像dockers镜像的进一步理解 2 Docker镜像commit操作实例案例内容是ubuntu安装vim 3 将本地镜像推送至阿里云4 将阿里云镜像下载到本地仓库5 后记 1 Docker镜像 镜像,是docker的三件套之一(镜像、容器、仓库)&#xff0…

uniapp微信小程序使用vant组件库

1. vant组件库(微信小程序版本)官网地址 地址: vant组件库(微信小程序版本) 2. uniapp微信小程序引入 <1>. 去到GitHub中将资源克隆到本地,地址: vant-weapp <2>. 到本地把文件拷贝到我们的uniapp微信小程序项目中 在项目的目录下新建一个文件wxcomponents&#…

iOS 18.2开发者预览版 Beta 1版本发布,欧盟允许卸载应用商店

苹果今天为开发人员推送了iOS 18.2开发者预览版 Beta 1版本 更新&#xff08;内部版本号&#xff1a;22C5109p&#xff09;&#xff0c;本次更新距离上次发布 Beta / RC 间隔 2 天。该版本仅适用于支持Apple Intelligence的设备&#xff0c;包括iPhone 15 Pro系列和iPhone 16系…

Spring Web MVC 入门

1. 什么是 Spring Web MVC Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从从⼀开始就包含在Spring框架中。它的 正式名称“SpringWebMVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它通常被称为"Spring MVC". 什么是Servlet呢? Ser…

开拓鸿蒙测试新境界,龙测科技引领自动化测试未来

在当今科技舞台上&#xff0c;鸿蒙 OS 以非凡先进性强势登场&#xff0c;打破传统操作系统格局&#xff0c;为软件测试领域带来全新机遇与艰巨挑战。 一、鸿蒙 OS 的辉煌崛起 &#xff08;一&#xff09;壮丽发展历程与卓越市场地位 鸿蒙 OS 的发展如波澜壮阔的史诗。2023 年…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十二)拓展图优化库g2o(一)框架

【转载】理解图优化&#xff0c;一步步带你看懂g2o框架 文章来源&#xff1a;理解图优化&#xff0c;一步步带你看懂g2o框架 小白&#xff1a;师兄师兄&#xff0c;最近我在看SLAM的优化算法&#xff0c;有种方法叫“图优化”&#xff0c;以前学习算法的时候还有一个优化方法…

Python量化交易(二):金融市场的基础概念

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年10月学习赛的Python量化交易学习总结文档&#xff1b;在现代社会中&#xff0c;投资已成为个人、机构和政府追求财富增长和资源配置的重要方式。…