Flutter 之 HTTP3/QUIC 和 Cronet 你了解过吗?

news/2024/5/22 8:33:11

虽然 HTTP3/QUIC 和 cronet 跟 Flutter 没太大关系,只是最近在整理 Flutter 相关资料时发现还挺多人不了解,就放到一起聊聊。

本篇也是主要将现有资料做一些简化整合理解。

前言

其实为什么会有 HTTP3/QUIC ?核心原因还是现有协议已经无法满足需求,说个最简单又不严谨的例子:

当你在家里拿着手机用 Wi-Fi 下片,这时候觉得饿了要下楼吃饭,然后你带着手机离开了家里,期间一直没有退出 App 的打算,这个过程手机流量会从 Wi-Fi 变成 5G 网络,那么网络链路就会变成了一个全新的网络环境,从 Wi-Fi 到 5G 会是全新的 IP 地址,那么作为新的链接, TCP 就无法复用之前的数据和状态,也就是之前链路就断了,那么下载行为可能就会被打断,而你直到温饱之后要用,才发现资源还没下载完成。

我们知道, HTTP/2 时代,每个网络请求我们都要经历多次 TCP 握手,特别现在基本都强制了 HTTPS ,所以 TLS 加密握手也不可或缺,但是在移动场景下,其实用户的网络环境极有可能在不停的发生变化,所以用户在移动过程中,TCP 链接极有可能被迫打断。

在 App 使用过程中,重启 TCP 连接会带来一些不好的体验,例如等待新的握手、重新开始下载、重建上下文等延迟,而 QUIC 其中就包括解决这一问题的实现,通过 connection migration 实现链路复用,后续我们会详细聊到。

QUIC

其实只要说到 HTTP/3 就离不开 QUIC (Quick UDP Internet Connections),因为 QUIC 是一个通用传输协议,它是 HTTP/3 的灵魂所在,而神奇之处也在于,它是运行在 UDP 的协议的基础上

大家对于 UDP 应该不陌生,因为相较于 TCP ,它相对不可靠,因为 UDP 不提供任何特性,例如它不会通过握手建立连接,如果包丢失也不会获得自动重传,所以它一直以来都被冠以「不可靠」的称号。

那么 UDP 有什么优点?那肯定是快~因为 UDP 不需要等待握手,也没有队头阻塞,所以它的性能一直很好,那 QUIC 建立在 UDP 之上就是为了性能吗

其实并不全是,或者是关键因素并不是,因为如果把 QUIC 作为一个直接运行在 IP 之上的全新独立协议,那么就意味着 HTTP/3 会无法兼容现有的许多硬件设备,这明显并不现实,但是如果构建在 UDP 上,那么 QUIC 就拥有更好的兼容和部署支持

所以最终落地的结果就是: QUIC 在 UDP 之上重新实现了一套「更高效的 “new TCP”」 的通用协议

当然,如果你硬要简单说 HTTP/3 是将 TCP 换成了 UDP 也说得通,只是并不是因为 UDP 更快,而是为了 QUIC 能更好兼容部署,并且 QUIC 本身就是一套基于 UDP 的全新的高级的 “TCP”

那么 QUIC 有哪些优秀的地方呢?其中就包括前面说的在移动环境下让连接可以保持更长时间

QUIC 支持连接迁移( connection migration )

我们前面知道了,当用户手机在 Wi-Fi 和 5G 网络进行切换时,TCP 链接会出现中断,如果我们定义 App 和服务器之间的链接是通过 「App IP + App 端口 + 服务器 IP + 服务器端口」 这样四个元素来表示一个链接,那么 Wi-Fi 和 5G 网络的时候,App 端的 IP 变了,那么对于服务端而言,这就是一个全新的链接,所以旧的 TCP 链接就无法被复用。

为了解决这个问题,QUIC 提出了连接标识符(CID, connection identifier),每个连接都在前面提到的四个元素之上分配了另一个 CID 编号,可以在 App-服务器端点之间来唯一标识它。

简单说,因为这里 CID 在 QUIC 中的传输层定义,所以它不会因为切换网络时发生改变,比如下图所示,一般情况下 CID 是包含在每个 QUIC 数据包的前端,而 CID 也是 QUIC header 中少数几个没有加密的数据。

通过 CID ,前面提到的四个元素里,就算 App IP 发生变化,QUIC 服务器和 App 只需要看下 CID,就能知道这其实还是之前的同一个连接,不需要重新握手,可以继续复用之前的下载状态,这也是前面提到过的 connection migration 。

当然,前面这个介绍相对简化,如何考虑到安全问题,CID 不会被直接使用,而是使用映射。

假设 App 和服务器都知道有 CID A、B 、C 都是映射到连接 X, 然后 App 可能会在 Wi-Fi 上会使用 A 标记数据包,而在 5G 上使用 B 标记 ,而映射的列表在 QUIC 中是完全加密,从而让黑客只知道 A、B、C,但是不知道 X 的存在。

当然,这也还是简化后的逻辑,只是为了更好理解,现实中 CID 的相关逻辑更加复杂,只是通过这些,大家应该就可以更快速理解 QUIC 为什么可以做到 connection migration 和其关键实现理念。

就这样,有了 QUIC 支持,在移动场景中,当网络切换时,可以看到如下图右侧使用 QUIC 手机很快便响应了请求,而左侧手机因为需要建立新的链路,所以需要等待超时后,重新握手成功再请求的效率对比。

TLS 集成

其实通过一开始的架构图,大家应该也可以看出来,和 HTTP/2 不同的是,QUCI 他直接集成了 TLS ,其目的就是加快和减少 HTTPS 请求是所需的时间。

因为在以前使用 HTTPS 请求时, HTTP 数据需要先由 TLS 加密,再由 TCP 传输,虽然 TLS 随着版本发展所需的加密握手次数已经得到优化,但是相比较起来,加密所带来的开销还是客观存在。

而在 QUIC 里就不一样了,QUIC 将 TLS 进行了封装,所以,对于 TCP 模式下 TLS 和 TCP 协议都需要单独握手, QUIC 将传输和加密握手合并为一次握手,节省了往返时间,但这也表明了 QUIC 必须使用 TLS, HTTP/3 下会是始终完全加密的状态,同时 QUIC 还加密它的(除了前面的 CID 等)数据包头字段,甚至传输层信息一般情况下都不能再被中间件读取。

所以,QUIC 默认深度加密,与之前的 TCP 相比,他也可以在一定程度节省 TLS 的开销,当然,QUIC 使用 TLS 单独加密每个数据包,而 TLS-TCP 可以同时加密多个数据包,所以 QUIC 也可能在高吞吐量的场景中变慢。

优化多路复用字节流

简单说,多路复用字节流就是单一 TCP 连接下载不同的资源,在传输时将不同文件的数据混合,比如 ABC 三种数据混合在一起传输。

而在 TCP 时代,TCP 是不知道多路复用字节流里数据的混合情况,也即是 TCP 不知道数据是 ABC,它直管传输数据,如果这时候 C 出现数据丢失, TCP 会认为整个数据传输出现丢失,从而导致整个链路里其他 AB 因为这个等待而变慢,这就是传说中的队头阻塞问题。

而 QUIC 的在某种意义上解决了传输层的队头阻塞问题,因为 QUIC 会知道有多路复用的多字节流存在,是真正意义上“理解了”多路复用,所以它可以在每个流的基础上执行丢包监测和恢复逻辑。

当然,这也造成了 TCP 和 QUIC 出现了本质的不兼容区别,QUIC 「理论上」来说是不兼容 HTTP/2 运行,因为 HTTP/2 还包括在单一 TCP 连接上运行多个流的概念。

其实 TCP 的设计目的从来不是在单一 TCP 上传输多个独立的文件,只是因为现实场景用到了,所以才有这样奇怪的兼容方式,而 QUIC 通过在传输层传输多个字节流以及在每个流基础上处理丢包问题,来解决 TCP 上一直存在的问题。

总的来说,QUIC 算是 TCP 的不兼容升级,而又由于它基于 UDP 实现,所以可以兼容已有的设备运行,并且集成了 TLS,默认全加密,支持 connection migration 等,在不可靠的网络场景下也可以实现更可靠的网络运行

QUIC 下的 Flutter :Cronet

既然我们知道 HTTP/3 和 QUIC 可以得到更好的体验,那就不得不说 Cronet,因为 Cronet 是 Chromium 网络堆栈,所以才被称为 Cronet ,它和 Chromium 使用相同的网络引擎。

使用 Cronet 最重要的意义是,它能够同时支持 TCP 协议和 QUIC 协议,一般情况下 App 发送请求时会说明“我支持 QUIC” ,然后服务端收到请求后,根据自身情况确实是否使用 QUIC 。

目前的说法是,只要 Cronet 知道了服务端支持 QUIC ,那么 Cronet 后续请求就会开始使用 QUIC , QUIC 的协议发现过程是通过识别响应头中的特殊字段来实现

而 Cronet 核心网络引擎完全基于C/C++,所以它除了可以在 Android 中使用之外,也可以通过 FFI 的方式被 Dart 使用,在 Google 产品里, YouTube、 Google App、 Google Photos、 Maps 等都是用 Cronet 来处理网络请求,所以总的来说,Cronet 还是相对可靠的

所以其实对于 Cronet 而言, Flutter 和 Android 都是大差不差的情况。

Cronet 在 Flutter 得推进主要是依赖 Dart 语言的发展进程,例如:

  • Dart 2.18 提供了对两个对于 package:http 特定于平台的 http 库的实验性支持:

    • cupertino_http 基于 NSURLSession 的 macOS/iOS 支持。

    • cronet_http 基于 Cronet,Android 上的网络库支持。

  • Dart 3.2

    • 改进 package:jnigen 实现 Java 和 Kotlin 的直接调用支持,现在可以将 package:cronet_http(Android Cronet HTTP 客户端的包装器)从手写绑定代码迁移到自动生成的包装器

目前 Flutter 使用 Cronet 可以通过引入 cronet_http 包,新版的 dio 内也实现了对应的 cronet_adapter ,如果你使用了 dio ,基本就可以直接使用 Cronet。

对于 Cronet 的使用,也可以分为 使用Google Play 支持版本和使用嵌入式 Cronet 支持版本

  • 如果你的 App 使用 GP 服务,那么其实可以不额外植入 Cronet 依赖,这样的好处就是 Cronet 的更新迭代完全和你的 App 没有关系,升级维护完全交给 GP 负责,相对体积也会小很多。

  • 如果你不使用或者没条件使用 GP 服务,那么也可以使用嵌入式的运行方式,例如 flutter run --dart-define=cronetHttpNoPlay=true

而如果你使用 Dio,那么使用 Cronet 则非常“简单”,只需要一行配置即可完成,不过目前来说,Cronet 只会在 Android 生效,在 iOS 上 NativeAdapter 使用的是基于 NSURLSessioncupertino_http

final dioClient = Dio();
dioClient.httpClientAdapter = NativeAdapter();

为什么 iOS 使用 NSURLSession ?因为 iOS 15 和 macOS Monterey 默认就启用适配了 HTTP/3

最后

本篇主要还是基于科普性质居多,核心还是简单的告诉大家,什么是 HTTP/3 和 QUIC ,QUIC 和 TCP 的区别和优势,最后是 Cronet 的介绍已经如何在 Flutter 里使用 QUIC。

目前基本云厂商都已经支持了 QUIC 配置,所以如果你还没开始接触 HTTP/3 ,现在也许是时候可以试试了,不过我认为,其实也许你的项目已经在使用 HTTP/3 ,只是你还没发现而已。

参考资料:

  • https://unsuitable001.medium.com/package-cronet-an-http-dart-flutter-package-with-dart-ffi-84f9b69c8a24

  • https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/

  • https://calendar.perfplanet.com/2020/head-of-line-blocking-in-quic-and-http-3-the-details/

  • https://pub.dev/packages/cronet_http

  • https://www.youtube.com/watch?v=YWiRef3wOYY


http://www.mrgr.cn/p/80764771

相关文章

基于GAN的图像补全实战

数据与代码地址见文末 论文地址:http://iizuka.cs.tsukuba.ac.jp/projects/completion/data/completion_sig2017.pdf 1.概述 图像补全,即补全图像中的覆盖和缺失部分, 网络整体结构如下图所示,整体网络结构还是采取GAN,对于生成器,网络结构采取Unet的形式,首先使用卷积…

Spyder修改python解释器

Spyder更改为python3.10解释器因为系统安装的python版本为3.10,但是官网下载最新的Spyder内置python版本为3.7.9,强迫症一犯就想着更改成3.10,步骤如下: 偏好里面更改控制台的运行方式(根据个人习惯设置就行,这里设置在专用控制台运行) 安装IPython先用pip3 list查看一下…

你的数据库用对索引了吗?一文揭秘PolarDB XPlan索引选择

深度解读PolarDB分布式版XPlan的索引选择​对于数据库来说,正确地选择索引是基本要求,选错索引轻则导致查询缓慢,重则导致数据库整体不可用。PolarDB分布式版存在多种不同的索引:局部索引、全局索引、列存索引、归档表索引。局部索引就是单机数据库上常用的索引,目的是避免…

论文复现---MUTANT

Robust anomaly detection for multivariate time series through temporal GCNs and attention-based VAE 基于时序神经网络和基于注意力的VAE的多变量时间序列鲁棒异常检测 https://github.com/Coac-syf/MUTANT * numpy1.21.2* torch1.9.1* scipy1.7.1* scikit-learn0.24.2*…

vue中websocket的使用---详解

一、什么是webscoketWebSockets 是一种先进的技术,它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此 API,可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。WebSockets 这种技术中有一个接口名为WebSocket,它是一个用于连接 W…

ARP代理

10.1.0.1/8 和10.2.0.1/8是在同一个网段 10.1.0.2/16 和10.2.0.2/16 不在同一个网段 10.1.0.1/8 和10.1.0.2/16 是可以ping通的 包发出来了,报文有发出来,目的地址是广播包 广播请求,发到路由器的接口G 0/0/0 target不是本接口&#xff0…

Neo4j 图形数据库中有哪些构建块?

Neo4j 图形数据库具有以下构建块 - 节点属性关系标签数据浏览器 节点 节点是 Graph 的基本单位。 它包含具有键值对的属性,如下图所示。 NEmployee 节点 在这里,节点 Name "Employee" ,它包含一组属性作为键值对。 属性 属性是…

隐式/动态游标的创建与使用

目录 将 emp 数据表中部门 10 的员工工资增加 100 元,然后使用隐式游标的 %ROWCOUNT 属性输出涉及的员工数量 动态游标的定义 声明游标变量 打开游标变量 检索游标变量 关闭游标变量 定义动态游标,输出 emp 中部门 10 的所有员工的工号和姓名 Orac…

uniCloud云函数概述---云对象

云对象是普通云函数的升级版,功能和云函数是一样的。它在大多数场景下替代了普通云函数。 云对象是对象化的云函数,比如一个文章云对象,它可以包括文章的创建,文章的删除,文章的编辑等功能。 (一句话描述云对象: 等同于PHP后端部份)一、创建云对象 打开项目,找到uniCl…

Docker Container (容器) 常见命令

Docker 容器的生命周期 什么是容器? 通俗地讲,容器是镜像的运行实体。镜像是静态的只读文件,而容器带有运行时需要的可写文件层,并且容器中的进程属于运行状态。即容器运行着真正的应用进程。容 器有初建、运行、停止、暂停和删除…

JSNeat: Recovering Variable Names for Minified Code with Usage Contexts

发表:ICSE,2019,德克萨斯大学达拉斯分校计算机科学系,Tien N. Nguyen团队(https://personal.utdallas.edu/~tien.n.nguyen/) 开源:https://github.com/trunghieu-tran/RecoverJSName-JSNeat 主要内容本文提出了一种基于信息检索(IR)的方法JSNEAT来恢复经过混淆的JS代码…

HarmonyOS 简易封装网络请求框架

设计思路网络请求框架的设计目标是简化 HTTP 请求的发送和响应处理过程。为了实现这一目标,我们定义了几个核心组件:IHttpRequest: 定义了发送 HTTP 请求的基本操作,如设置 URL、请求头、请求参数等。 IHttpListener: 定义了 HTTP 请求完成后的回调方法,用于处理请求的成功…

QOJ5717

好,好难。非常好题目,拜谢 Itst。不过如果我去考这场估计就哈哈了。\(k = 3\) 都能卡。 还是要避免一条路走到黑啊。懂得变通。\(k=1\) 是送的。 \(k=2\) 较为平凡,只需要将相对大的、相对小的各放一起。 \(k=3\) 不简单了。首先二分答案 \(mid\),经过 800 万年转换视角,钦…

运行程序时出现mschrt20.ocx未注册找不到控件问题

其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个mschrt20.ocx文件(挑选合适的版本文…

libtorch模型预测环境配置说明

1、cuda环境 (1)更新nvidia显卡驱动 首先在NVIDIA官网下载与电脑显卡类型一致的显卡驱动,我的显卡是quadro P2000,下载对应的显卡驱动程序安装。 474.82-quadro-rtx-desktop-notebook-win10-win11-64bit-international-whql.exe (2)cuda的安装 显卡驱动安装完成后,NVIDI…

每日两题2

不同路径 class Solution { public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m1, vector<int>(n1,0));//创建dp表dp[0][1] 1;//初始化//填表for(int i 1; i < m; i){for(int j 1; j < n; j){dp[i][j] dp[i-1][j] dp[i][j-1];}}ret…

支持标准OPS接口,通用型RK3568工控板上新!

HD-RK3568-OPS主板基于HD-RK3568-CORE 工业级核心板设计,搭载1.8GHz主频的高性能ARM处理器,适用于工业现场应用需求。主板支持标准OPS接口、支持前后HDMI双路输出,具有即插即用、操作简单的特点,亦适用于数字标牌、自助终端、教育一体机等应用场景。 ​ 主要功能包括: OP…

5-02. 创建 AudioMixer 实现音乐音效的控制和切换

创建 AudioMixer修改 AudioMixer 可以增加 Snapshots可以增加 Groups创建一个只有背景音乐的快照静音的快照暴露音量 选中 Music,然后右键 Music然后就能在 Exposed Parameters 看到暴露出来的变量可以改名为 MusicVolume用同样的方法暴露出 Ambient 并修改名字用同样的方法暴…

MBR40100PT-ASEMI肖特基二极管MBR40100PT

MBR40100PT-ASEMI肖特基二极管MBR40100PT编辑:ll MBR40100PT-ASEMI肖特基二极管MBR40100PT 型号:MBR40100PT 品牌:ASEMI 封装:TO-247 最大平均正向电流(IF):40A 最大循环峰值反向电压(VRRM):100V 最大正向电压(VF):0.88V 工作温度:-40C~170C 反向恢复时间:5ns 芯…

【大数据与云计算】虚拟机安装Linux

前言&#xff1a;使用Linux系统对大数据学习必不可少&#xff0c;本文主要介绍虚拟机安装linux的流程 文章目录 一、 下载VMware二、下载Linux三、安装Linux 一、 下载VMware 官网链接 下载VMware-player&#xff0c;一直下一步安装即可。 二、下载Linux 点击链接直接下载&…