作者:赵咏
QUIC的发音类似于Quick,实际上也确实很快。它可以很好地解决应用在传输层和应用层面临的各种需求,包括处理更多的连接、安全性以及低延迟。
目前在互联网领域,QUIC可以说刮起了新一代互联网传输协议的风。对开发者而言,了解QUIC更是有助于时延敏感性应用以及音视频、购物支付等应用场景的体验提升。

*** 0RTT,建立低延迟传输**
传统的TLS协议,需要经过两级握手实现用户数据的传输。第一级包括TCP的三次握手,至少需要一个来回;第二级是TLS协议的握手,通过ClienHello、ServerHello几次握手的数据包协商后才能开始用户数据传输。
虽然TLS1.3在TLS握手阶段进行了优化,支持在首包ClientHello传输数据,但TCP的握手还是无法节省。QUIC协议则抛弃了TCP协议,改用UDP作为底层传输协议,进一步压缩了TCP三次握手所带来的时延,达到了真正的0RTT。这一优势对时延敏感型的应用很有吸引力,也给视频类应用提供了切换至QUIC协议的动力。
*** 加密传输**
大部分互联网公司都十分注重用户的安全隐私,始终持续推进数据的加密传输。这项工作需要两个协议支撑,分别是HTTP协议和DNS协议。
(1) HTTP协议从1.1版本升级到2.0再到3.0,本身并没有涉及加密的内容,仅在时延问题上改进。但与HTTP协议伴生的TLS协议专职进行加密,从TLS1.2升级到了TLS1.3,不仅增强了加密的强度,还将原先的明文握手部分进行了大幅加密。甚至,TLS协议计划未来将所有的握手部分均加密。
(2) DNS协议与HTTP协议也是伴生状态,但不可避免的会泄露HTTP协议中的域名信息。因此,DNS的加密一般会同时进行。
目前主流的解决方案是使用TLS进行加密,但QUIC协议拥有和TLS类似的加密能力,且性能更好。这打破了TLS协议对加密的垄断,成为其最大竞争者。
很多年前,谷歌和Meta(原Facebook)对QUIC协议分别进行了研究,甚至Facebook还实现了一个TCP版本的QUIC。后来,他们在研究上分列两个阵营,一个是谷歌的gQUIC,另一个是IETF-QUIC。不过最后,他们达成了一致,均归为IETF-QUIC阵营,也就是现今QUIC的雏形。
作为主推者,谷歌和Facebook旗下的App已大量使用QUIC进行通信。那么如今他们以及各大互联网厂商都在QUIC上有哪些进展呢?
谷歌:作为使用广泛的移动操作系统Android,其自带浏览器组件Webview均默认支持QUIC,Chrome及其衍生浏览均支持QUIC。还有一些和用户生活连接紧密的App也会尝试使用QUIC,比如Youtube、Gmail、Google map、Google Play等。这些在支持使用的场景下都会默认进行QUIC的传输。
Facebook:Facebook、Messenger、Instagram、Whatsapp等旗下较为知名的App和谷歌使用类似的QUIC策略。
Apple:苹果在QUIC上的策略没有那么激进,但已经将QUIC作为未来趋势进行准备,包括QUIC上线所配套的DoH服务器。另外,苹果已经在最新的iCloud+ Private Relay中使用了QUIC作为代理传输协议。
CloudFlare:作为一个CDN厂商,ClouFlare一直大力推动QUIC的使用,覆盖大量chrome+小网站模式下的流量,让这些流量默认使用QUIC。
Snapchat:跟随着Google的脚步,这款较为风靡的聊天软件,也大量使用了QUIC。
国内互联网厂商:快手、搜狐视频主力使用QUIC传输视频,目前是国内推进最快的。微信、淘宝、爱奇艺、抖音、百度已在部分流量或者部分时延场景下启用QUIC。使用QUIC逐渐成为国内互联网厂商的潮流。
经过长时间的演变以及两个阵营的研究,QUIC协议具有很多分支和变种。这里我们省略一些前期变化的叙述,聚焦当前的情况展开。目前,QUIC协议主要有两大分支版本。

CRYPTO包含具体的握手参数,这是与gQUIC和IETF QUIC区别最大的地方。但它们的作用类似,都是提供域名、加密参数之类的握手所需要的信息。下图则是gQUIC中的格式,是谷歌自己定义的:

在IETF QUIC里的CRYPTO装的是一个TLS的ClientHello,基本上直接复制了TLS的格式。下图是IETF QUIC的CRYPTO格式,从外部格式看这是两个QUIC分支最大的区别点:

外部能看到的格式介绍到这里,已经说明了90%,其他部分在Wireshark里面有比较明确的解释。此外,最新版的QUIC(两个分支)均使用了Encrypted ClientHello机制,前面介绍的ClientHello在流量里面是“加密”状态,看起来是一些随机的字节,只有最开始的几个字节用来区分不同的QUIC版本。但这个“加密”的秘钥就藏在ClientHello包里面,可以现场计算出真正的秘钥并解密。因此,Wireshark能够看到明文的ClientHello内容。这种“加密”类似当年的P2P协议,都是为了增加DPI设备的处理难度,最终需要拼CPU算力。如果CPU算力不够则看不到明文。
Wireshark提供了QUIC流量的解密功能,有秘钥就能看到加密前的具体内容。这样我们也就能直观的看到QUIC的交互过程。事实上,QUIC承担了TCP的功能,主要是可靠性传输的保障能力。从下图可以看出,内部会传输大量的ACK报文,用来确认数据已经收到,基于此再产生重传等拥塞控制相关的能力。

除了可靠性传输的保障能力,QUIC内部存在stream机制。每个stream都可以被认为是一个独立的流,这样QUIC本身就是一个大的加密传输隧道。QUIC内部实际传输数据的协议一般是HTTP3,这让QUIC和HTTP3产生了强绑定,很多时候大家会把这二者当成是一个东西。Wireshark目前并没有解析HTTP3,只能看到一些二进制的数据。但HTTP3继承了HTTP2,数据带有压缩,短短的几个字节可能就是一个巨大请求压缩后的结果。

综上所述,QUIC协议是一个结合多种优秀特性的互联网传输新协议,自然也成为了互联网各大厂商的新宠儿。对此,华为也推出了HMS Core网络加速套件——hQUIC Kit,帮助开发者在应用中快速支持QUIC协议,再辅以智能拥塞算法,最终为用户提供更快的连接建立速度,更强的抗丢包能力以及更高的吞吐量。hQUIC适用游戏、视频通话、在线TV/VOD、VR实时广播等应用场景,其服务优势有:
简单易用:提供简单易用的编程接口,屏蔽网络细节。
兼容性:兼容gQUIC协议,支持Cronet接口。
移动网络体验提升:提升弱网环境对用户的体验。
更多hQUIC Kit 信息,请参见:
https://developer.huawei.com/consumer/cn/hms/huawei-hQUIC/?ha_source=hms1
了解更多详情>>
访问华为开发者联盟官网
获取开发指导文档
华为移动服务开源仓库地址:GitHub、Gitee
关注我们,第一时间了解 HMS Core 最新技术资讯~
我有一个Rails项目,其中一个常量在处理请求时在某个时刻被破坏。我正在使用mime/types和restclientgem。restclient模块定义了MIME的扩展,其中包含type_for_extension方法。moduleRestClient...defstringify_headersheadersresult[key]=target_values.map{|ext|MIME::Types.type_for_extension(ext.to_s.strip)}.join(',')...endendendmoduleMIMEclassTypesdeftype_for_ext
我非常困惑:这几乎是从RoR操作邮件程序指南中复制/粘贴的,但它会引发语法错误:classContacta_name,:company=>a_company,:phone=>a_phone,:email=>a_email,:comments=>a_comments}endend错误是:app/models/contact.rb:9:syntaxerror,unexpectedtASSOC,expecting'}'body{:name=>a_name,:company=>a_company...^app/models/contact.rb:9:syntaxerror,unexpected
今天,我无意中发现了Ruby中神秘的Data类,但我找不到任何有用的信息来说明它的作用或它为什么存在。我假设它是语言实现本身的一部分。有人知道它的作用吗?mbp-scott:~scott$irbruby-1.9.3-p0:001>Data=>Dataruby-1.9.3-p0:002>Data.is_a?Module=>trueruby-1.9.3-p0:003>Data.is_a?Class=>trueruby-1.9.3-p0:004>Data.ancestors=>[Data,Object,Kernel,BasicObject]ruby-1.9.3-p0:005>Data.met
当我的应用启动时,情节板启动屏幕显示我的图像如预期的,但部分被灰色盒子覆盖。有人可以让我知道图像框的来源吗?启动屏幕上唯一的东西是页面上的图像。这是屏幕截图:看答案您是否检查了启动图像是否损坏了?
以下脚本包含一个非常奇怪的错误。我想检查一个值是否为正整数。为此,我乘以100以将值括在十进制中。如果我测试0.07,脚本计算的不是值7,而是值7.00000001。我可以四舍五入这个值,但我想知道为什么这个值是这样计算的。varisPositiveInt=function(i){i=i*100;return((i%1)==0&&i>=0);};Tryitout!0.05、0.06和0.08效果很好。但是0.07会发生什么?如果有人能向我解释这一点,我会很高兴。 最佳答案 那是因为javascript在内部将所有内容转换为doubl
我正在开发一个非常复杂的HTML5应用程序(主干、Marionette、jQuery、下划线、Handlebars、Bootstrap等),在应用程序的深处是一个带有表单的模式弹出窗口。当模式弹出时,当您第一次单击任何表单域时,表单域会自行取消选择。第一次单击后,您可以正常使用该表单。当应用程序最终加载到生产中的iFrame时(不要问),当您第一次单击任何表单字段或将鼠标悬停在任何按钮上时,整个页面将向下滚动,直到表单位于内部的div元素的顶部模态框位于页面顶部,但在它执行一次之后就不会再执行一次(混淆了吗?是的,它很复杂且分层)。我什至不知道如何开始调试这个问题(数千行代码,两把库)
vart=newDate();t.getTime()+-864e5;第二行末尾的“+”后面的古怪代码在做什么?这可能很难理解,因为我怀疑这是他们试图保护自己免受抓取的方法之一。 最佳答案 它是一个有效的JavaScript数字,表示一天24小时中的毫秒数。1000*60*60*24or86400000or864e5 关于带有神秘附加字符的JavascriptDategetTime()代码片段,我们在StackOverflow上找到一个类似的问题: https:
我检查了GoogleChrome中的javascript异常。我注意到函数getmessage、getstack、setmessage和setstack。我trycatch此异常并运行alert(e.get_message());只是为了得到一个错误。我还尝试运行alert(e.getmessage());,这显然由于空格返回了另一个错误。这些神秘的方法是什么,开发人员如何调用它们? 最佳答案 它们是属性访问器。它们是在您获取或设置属性时运行的有效函数。e.message;//gettere.message="foobar";//s
概括我想要做的很简单:1a.如果图像不是某种类型的本地存储(例如IndexedDB),则从服务器读取图像作为字节数组,放入本地存储(作为字节数组或对文件的引用,我不在乎)1b.如果图像在本地存储中,则从本地存储中读取字节数组。将此字节数组显示为html页面中的图像。不知何故,在Blob、objectURL、indexedDB和缓存之间,它都变得过于复杂,并表现出一些奇怪的行为。如果有一种方法可以将ArrayBuffer直接粘贴到图像中,而不是先转换为Blob,然后再转换为ObjectURL,那么我可能会采用这种方法,因为它更简单,并且摆脱了有问题的Blob和一些不必要的步骤。如果您想查
我正在构建一个chrome扩展。当我在本地测试它时,我可以采取一些导致CSP违规的操作:RefusedtoruntheJavaScriptURLbecauseitviolatesthefollowingContentSecurityPolicydirective:"script-srchttps://apis.google.com'self'".Eitherthe'unsafe-inline'keyword,ahash('sha256-...'),oranonce('nonce-...')isrequiredtoenableinlineexecution.但是,我的代码没有任何内联ja