探究QUIC协议:基于UDP的可靠传输之路

为什么需要基于 UDP 实现可靠传输

主要是 TCP 协议四个方面的缺陷:

  • 升级 TCP 的工作很困难;
  • TCP 建立连接的延迟;
  • TCP 存在队头阻塞问题;
  • 网络迁移需要重新建立 TCP 连接;

因此,基于UDP实现可靠传输并不是重复造轮子,而是根据特定的需求和场景选择合适的工具和机制,以满足应用程序的要求。

QUIC 协议

现在市面上已经有基于 UDP 协议实现的可靠传输协议的成熟方案了,那就是 QUIC 协议,已经应用在了HTTP/3。

这次,聊聊 QUIC 是如何实现可靠传输的?又是如何解决上面 TCP 协议四个方面的缺陷

QUIC 是如何实现可靠传输的?

要基于 UDP 实现的可靠传输协议,那么就要在应用层下功夫,也就是要设计好协议的头部字段。

拿 HTTP/3 举例子,在 UDP 报文头部与 HTTP 消息之间,共有 3 层头部:

Packet Header

Packet Header 首次建立连接时和日常传输数据时使用的 Header 是不同的

 

        QUIC 也是需要三次握手来建立连接的,主要目的是为了协商连接 ID。协商出连接 ID 后,后续传输时,双方只需要固定住连接 ID,从而实现连接迁移功能。所以,你可以看到日常传输数据的 Short Packet Header 不需要在传输 Source Connection ID 字段了,只需要传输 Destination Connection ID。

        Short Packet Header 中的 Packet Number 是每个报文独一无二的编号,它是严格递增的,也就是说就算 Packet N 丢失了,重传的 Packet N 的 Packet Number 已经不是 N,而是一个比 N 大的值。

为什么这样子设计?

        TCP 在重传报文时的序列号和原始报文的序列号是一样的,也正是由于这个特性,引入了 TCP 重传的歧义问题。当 TCP 发生超时重传后,客户端发起重传,然后接收到了服务端确认 ACK 。由于客户端原始报文和重传报文序列号都是一样的,那么服务端针对这两个报文回复的都是相同的 ACK。

        这样的话,客户端就无法判断出是「原始报文的响应」还是「重传报文的响应」,这样在计算 RTT(往返时间) 时应该选择从发送原始报文开始计算,还是重传原始报文开始计算呢?

        RTO (超时时间)是基于 RTT 来计算的,那么如果 RTT 计算不精准,那么 RTO (超时时间)也会不精确,这样可能导致重传的概率事件增大

  • QUIC 报文中的 Pakcet Number 是严格递增的, 即使是重传报文,它的 Pakcet Number 也是递增的,这样就能更加精确计算出报文的 RTT。

  • 另外,还有一个好处,单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,支持乱序确认,当数据包Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动,这样就不会因为丢包重传将当前窗口阻塞在原地,从而解决了队头阻塞问题。

QUIC Frame Header

一个 Packet 报文中可以存放多个 QUIC Frame。

 

每一个 Frame 都有明确的类型,针对类型的不同,功能也不同,自然格式也不同。

我这里只举例 Stream 类型的 Frame 格式,Stream 可以认为就是一条 HTTP 请求,它长这样:

        在前面介绍 Packet Header 时,说到 Packet Number 是严格递增,即使重传报文的 Packet Number 也是递增的,既然重传数据包与丢失数据包编号并不一致,我们怎么确定这两个数据包的内容一样呢?

        所以引入 Frame Header 这一层,丢失的数据包和重传的数据包 Stream ID 与 Offset 都一致,说明这两个数据包的内容一致。这些数据包传输到接收端后,接收端能根据 Stream ID 与 Offset 字段信息将 Stream x 和 Stream x+y 按照顺序组织起来,然后交给应用程序处理。

QUIC 是如何解决 TCP 队头阻塞问题的?

在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (Stream)。

        但是 QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口

        假如 Stream2 丢了一个 UDP 包,也只会影响 Stream2 的处理,不会影响其他 Stream,与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。

QUIC 是如何做流量控制的?

        QUIC 是基于 UDP 传输的,而 UDP 没有流量控制,因此 QUIC 实现了自己的流量控制机制,QUIC 的滑动窗口滑动的条件跟 TCP 有一点差别,但是同一个 Stream 的数据也是要保证顺序的,不然无法实现可靠传输,因此同一个 Stream 的数据包丢失了,也会造成窗口无法滑动。

        QUIC 的 每个 Stream 都有各自的滑动窗口,不同 Stream 互相独立,队头的 Stream A 被阻塞后,不妨碍 StreamB、C的读取。而对于 HTTP/2 而言,所有的 Stream 都跑在一条 TCP 连接上,而这些 Stream 共享一个滑动窗口,因此同一个Connection内,Stream A 被阻塞后,StreamB、C 必须等待。

QUIC 实现了两种级别的流量控制,分别为 Stream 和 Connection 两种级别:

  • Stream 级别的流量控制:Stream 可以认为就是一条 HTTP 请求,每个 Stream 都有独立的滑动窗口,所以每个 Stream 都可以做流量控制,防止单个 Stream 消耗连接(Connection)的全部接收缓冲。

  • Connection 流量控制:限制连接中所有 Stream 相加起来的总字节数,防止发送方超过连接的缓冲容量。

QUIC 更快的连接建立

        对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手(1RTT),再 TLS 握手(2RTT),所以需要 3RTT 的延迟才能传输数据,就算 Session 会话服用,也需要至少 2 个 RTT。

        HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。

        但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果

如下图右边部分,HTTP/3 当会话恢复时,有效负载数据与第一个数据包一起发送,可以做到 0-RTT(下图的右下角):

 

QUIC 平滑迁移连接

基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。

那么当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立 TCP 连接

        而建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,给用户的感觉就是网络突然卡顿了一下,因此连接的迁移成本是很高的。

        QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,达到了连接迁移的功能。

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

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

相关文章

【python】(13)理解Python中的处理时间的模块

系列文章回顾 【python】(01)初识装饰器Decorator 【python】(02)初识迭代器Iterator 【python】(03)初识生成器Generator 【python】(04)python中实现多任务并发和并行的区别 【python】(05)如何使用python中的logging模块记录日志信息 【python】(06)理解Python中的 lambda 、…

ReentrantLock 原理

(一)、非公平锁实现原理 1、加锁解锁流程 先从构造器开始看,默认为非公平锁实现 public ReentrantLock() {sync new NonfairSync(); } NonfairSync 继承自 AQS 没有竞争时 加锁流程 构造器构造,默认构造非公平锁(无竞争,第一个线程尝试…

2023自适应霍夫曼编码High-performance RDHEI with adaptive Huffman code

RRBE 本文仅供自我学习使用,切勿转载和搬运,如有侵权,联系立删~ 方法总框架 首先由内容所有者生成原始图像像素点的标签映射; 然后数据隐藏者采用自适应霍夫曼编码将多个信息插入加密图像像素点;接收端进行数据提取和图像恢复。在数据提取之前,必须对标记的加密图像进行…

DC-7靶场

一.环境搭建 1.下载地址 靶机下载地址:https://download.vulnhub.com/dc/DC-7.zip 2.虚拟机配置 设置nat,打开靶机,遇到错误点重试和是 开启后如图所示即可 二.开始渗透 1.信息收集 首先找到靶机的ip地址 arp-scan -l 发现靶机的ip地址为192.168.…

影视接口支持资源站去插播,官解官替,切片

​​​​​uutb.centos.chat/jsonwjm.php/?url 公益提供,请友好调用

分布式ID生成方案总结

分布式场景下,需要保证每一个服务拿到的id是唯一的。本文讨论、分析、总结了一些常见的分布式ID生成方案 结论:技术上没有银弹,每种分布式id都有自己的使用场景。uuid适用于业务比较简单,对性能没有太高追求等。 目前主流是 基于数…

某手信息流如何跳V,达到精准数据回传?

在数字营销的新纪元中,快手磁力引擎凭借其卓越的推广能力,已经吸引了无数品牌的目光。而为了更有效地将快手上的流量转化为企业微信的用户,数灵通正逐渐崭露头角,成为品牌方的得力助手。今天,我们就来探讨一下&#xf…

Pytorch多机多卡分布式训练

多机多卡分布式: 多机基本上和单机多卡差不多: 第一台机器(主设备): torchrun --master_port 6666 --nproc_per_node8 --nnodes${nnodes} --node_rank0 --master_addr${master_addr} train_with_multi_machine_an…

【问题处理】蓝鲸监控-数据断点解决

本文来自腾讯蓝鲸智云社区用户:fadewalk 在问答社区看到有小伙伴在落地蓝鲸的过程中出现监控平台的grafana面板数据断点问题,往往出现这种问题,都比较的头疼。 如果将CMDB(配置管理数据库)比作运维的基石,…

嵌入式Linux:空洞文件

空洞文件(Sparse File)是一种在磁盘上并非完全分配存储空间的文件。它包含了一些逻辑上存在但物理上并未存储的数据。 空洞文件在多线程共同操作文件时具有极大的优势。当创建一个巨大的文件时,单个线程逐步构建文件会耗费大量时间。一种优化…

Soft Robotics:两栖环境下螃蟹仿生机器人的行走控制

传统水陆两栖机器人依靠轮胎或履带与表面的接触及摩擦产生推进力,这种对于表面接触的依赖性限制了现有水陆两栖机器人在低重力环境下(如水中)的机动性。利用生物自身的推进机制,人为激发生物运动行为,由活体生物与微机…

P1923 【深基9.例4】求第 k 小的数 Python 并未AC的一题

【深基9.例4】求第 k 小的数 题目描述 输入 n n n&#xff08; 1 ≤ n < 5000000 1 \le n < 5000000 1≤n<5000000 且 n n n 为奇数&#xff09;个数字 a i a_i ai​&#xff08; 1 ≤ a i < 10 9 1 \le a_i < {10}^9 1≤ai​<109&#xff09;&#xff…

电阻的妙用:限流、分压、滤波,助力电路设计!

电阻可以降低电压&#xff0c;这是通过电阻的分压来实现的。事实上&#xff0c;利用电阻来降低电压只是电阻的多种功能之一。电路中的电阻与其他元件&#xff08;电容、电感&#xff09;结合用于限流、滤波等。&#xff08;本文素材来源&#xff1a;https://www.icdhs.com/news…

AKShare 快速入门

AKShare 快速入门 查看数据 AKShare 快速入门 具体函数使用详情, 请查看 AKShare 文档 每个接口的示例代码 AKShare 数据接口一览 交易所期货数据 “get_cffex_daily”, # 中国金融期货交易所每日交易数据 “get_cffex_rank_table”, # 中国金融期货交易所前20会员持仓…

简明 Python 教程(第9章 面向对象编程)

本章开始介绍Python的面向对象编程&#xff0c;Python这种动态语言的面向对象和很多强类型语言如JAVA&#xff0c;C#&#xff0c;C等语法上区别还是比较大的&#xff0c;但总体思路基本还是相通的。面向对象编程是一种编程范式&#xff0c;它使用对象来表示现实世界中的实体&am…

C++ :STL中vector扩容机制

vector是STL提供的动态数组&#xff0c;它会在内部空间不够用时动态的调整自身的大小&#xff0c;调整过程中会有大量的数据拷贝&#xff0c;为了减少数据拷贝的次数vector会在调整空间的时候尽量多申请一些空间&#xff0c;这些预留出的空间可以很大程度上减少拷贝的发生。 在…

适合新手小白的wordpress详细安装教程

1、下载程序 到wordpress官方网站下载wordpress程序&#xff0c;官方下载地址&#xff1a;Download | WordPress.org China 简体中文。 下载最新版的wordpress程序 https://cn.wordpress.org/latest-zh_CN.zip 2、上传程序 上传程序前先确认主机是否符合安装的环境要求&…

文件压缩与解压命令

(1)tar 打包或解包 tar 将文件打包tar cvf xxxx.tar(打包好的名字) 需要打包的所有文件名 各参数的意义如下: c:创建包文件 f:指定目标为文件而不是设备; v:显示详细过程; t:显示包中的内容而不释放; x:释放包中的内容 z:GNU版本新加的,使得tar有压缩和解压的功能; 解…

爬虫基础训练题

1.抓取imooc网站实战课程部分的课程名称&#xff08;所有课程大概7页&#xff0c;抓取1到5页&#xff09;&#xff0c;并把所有课程名称存储为txt文件第一页地址 2.设置一个请求头&#xff08;headers&#xff09;&#xff0c;这是一个字典&#xff0c;用于在HTTP请求中设置请…

wordpress搬家修改前缀后台无法访问

wordpress更换域名后&#xff0c;后台不能访问&#xff0c;出现以下提示&#xff1a;Sorry, you are not allowed to access this page. 出现这种情况一般是因为更改了数据表的前缀了&#xff0c;比如&#xff0c;由原来的wp_改为了wp_louyuwu_ 解决办法&#xff1a; 1、打开…