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

虽然 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.mzph.cn/diannao/1245.shtml

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

相关文章

机器学习周记(第三十五周:语义分割)2024.4.15~2024.4.21

目录 摘要 ABSTRACT 1 语义分割基本概念 1.1 数据集格式 ​编辑 1.2 语义分割评价指标 1.3 语义分割标注工具 2 转置卷积 3 FCN网络结构基本原理 摘要 本周主要学习了语义分割的基本概念及其在计算机视觉领域中的应用。了解了语义分割的几种经典网络,如全卷…

linux系统密码重置的方法

在linux系统中忘记密码,重置(重启:shutdown -r now) 1、在启动 Linux 时,按键盘上的上下左右键来止 Linux 的正常启动。 2、按下e鍵进入安全模式 3、找到首行是linux16,末尾是UTF-8的段落,在后门…

Python中的设计模式与最佳实践

👽发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python中的设计模式与最佳实践 在软件开发中,设计模式是一种解决常见问题的经过…

【Django】调用django的pbkdf2_sha256加密算法测试

基于django搭建的系统中,用到pbkdf2_sha256((Password-Based Key Derivation Function 2))加密算法,这里做些代码测试、总结。 PBKDF2简介 PBKDF2是一种基于密码的密钥派生函数,用于从用户提供的…

2024-4-狼道

2024-4-狼道 2024-4-9 宋犀堃(堃通坤,多用于人名) fatux: 做人当如狗,和蔼可亲;做事当如狼,专注果决。 狼道 智慧生存的强者法则 走向卓越的成功之道 狼道,是追求卓越的野心&am…

C++_特殊类的设计和单例模式

文章目录 学习目标:1.请设计一个类,不能被拷贝2. 请设计一个类,只能在堆上创建对象3. 请设计一个类,只能在栈上创建对象4. 请设计一个类,不能被继承5. 请设计一个类,只能创建一个对象(单例模式) 特殊类的设…

如何在原生项目中集成flutter

两个前提条件: 从flutter v1.17版本开始,flutter module仅支持AndroidX的应用在release模式下flutter仅支持一下架构:x84_64、armeabi-v7a、arm6f4-v8a,不支持mips和x86;所以引入flutter前需要在app/build.gradle下配置flutter支持的架构 a…

《设计模式之美》- 总结

《设计模式之美》- 总结 第一章 概述 1.1 为什么学习代码设计 编写高质量的代码应对复杂代码的开发程序员的基本功职业发展的必备技能 1.2 如何评价代码的质量 1.2.1 可维护性 可维护性代码的特性:代码简洁、可读性好、可扩展性好代码分层结构清晰、模块化程度…

maven问题汇总

​ 1、报错 failed to transfer from http://0.0.0.0/ during a previous attempt. com.byd.xxx:xxx-parent:pom:1.1.0-SNAPSHOT failed to transfer from http://0.0.0.0/ during a previous attempt. This failure was cached in the local repository and resolution is no…

【Pytorch】PytorchCPU版或GPU报错异常处理(10X~4090D)

Pytorch为CPU版或GPU使用报错异常处理 文章目录 Pytorch为CPU版或GPU使用报错异常处理0.检查阶段1. 在conda虚拟环境中安装了torch2.卸载cpuonly3.从tsinghua清华源安装不完善误为cpu版本4.用tsinghua清华源安装成cpu错误版本5.conda中torch/vision/cudatoolkit版本与本机cuda版…

LeetCode - 283.移动零

题目链接&#xff1a; LeetCode - 283.移动零 题目分析&#xff1a; ​​​​​ 题解代码&#xff1a; #include<iostream> #include<vector> using namespace std;class Solution { public:void moveZeroes(vector<int>& nums) {for (int cur 0, des…

【GitBlit】Windows搭建Git服务器详细教程

前言 如果公司或个人想在 Windows 环境下搭建私有的 Git 服务器&#xff0c;那么这个开源的 GitBlit 是一个不错的选择。 Gitblit 是一个开源纯 Java 的用于管理、查看和服务 Git 存储库。它是一个小型的托管集中式存储库工具。支持 SSH、HTTP 和 GIT 协议&#xff0c;开箱即…

Java+springboot开发的医院智能导诊服务系统源码 自动兼容小程序与H5版本

智能导诊系统 一、什么是智慧导诊系统&#xff1f; 智慧导诊系统是一种医院使用的引导患者自助就诊挂号、精准推荐科室、引导患者挂号就诊的系统。该系统结合医院挂号及就诊的HIS系统&#xff0c;为患者带来全流程的信息指引提醒&#xff0c;可以在全院区构建一个精细化、移动…

IP-guard getdatarecord 存在任意文件读取

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 一、产品介绍 IP-guard是由溢信科技股份有限公司开发的一款终端安全管…

x-cmd ai | x openai - 用于发送 openai API 请求,以及与 ChatGPT 对话

介绍 Openai 模块是 Openai 大模型 Chatgpt 3 和 ChatGPT 4 命令行实现。x-cmd 提供了多个不同平台间多种 AI 大模型的调用能力。无论是本地模型还是 Web 服务上的模型&#xff0c;用户都可以在不同的 AI 大模型间直接无缝切换&#xff0c;并能把之前的聊天记录发送给新的大模…

CSS3 伪元素与伪类选择器区别、详解与应用实例

伪元素与伪类两者都是通过在选择器后附加一个特定的关键字来定义&#xff0c;遵循相似的语法规则&#xff0c;并在 CSS 规则块中设置相应的样式。伪元素 能够通过 content 属性添加或替换内容。例如&#xff0c;:before 和 :after 可以插入文本、图像或其他生成的内容。伪类 仅…

Tomcat核心组件深度解析

Server组件 Service组件 连接器Connector组件 容器Container组件

【研发管理】产品经理知识体系-产品创新管理

导读&#xff1a; 产品创新管理对企业的发展具有深远的影响&#xff0c;它不仅是企业保持竞争优势的关键&#xff0c;也是推动企业持续稳定发展的重要动力。因此&#xff0c;企业应高度重视产品创新管理&#xff0c;并采取有效的策略和方法来推动产品创新活动的开展。对于产品经…

第20天:信息打点-红蓝队自动化项目资产侦察企查产权武器库部署网络空间

第二十天 一、工具项目-红蓝队&自动化部署 自动化-武器库部署-F8x 项目地址&#xff1a;https://github.com/ffffffff0x/f8x 介绍&#xff1a;一款红/蓝队环境自动化部署工具,支持多种场景,渗透,开发,代理环境,服务可选项等.下载&#xff1a;wget -O f8x https://f8x.io…

MINIO安装的方法(WindowsLiunx)

2 minio安装教程 注&#xff1a;官方中文文档&#xff1a;MinIO对象存储 Windows — MinIO中文文档 | MinIO Windows中文文档 Liunx 安装方&#xff1a;MinIO对象存储 Linux — MinIO中文文档 | MinIO Linux中文文档 2.1 下载地址 https://dl.min.io/server/minio/…