QUIC数据通道:第一步


基于QUIC的数据通道被认为是当前SCTP传输的替代方案。 Google WebRTC工作组已经在对其进行试验:


让我们也尝试一下。 为此,我们将创建一个类似于WebRTC通道示例的单页应用程序以进行文本传输 -这是一个完全正常的示例(没有信令服务器),此外,这将使比较实现WebRTC DataChannel的方法变得容易。

在开始之前,让我们回顾一下DataChannel的基础。

简要介绍DataChannel


WebRTC的DataChannel允许参与者交换任意数据。 它们既可以可靠(在传输文件时非常有用),又可以不可靠(对于游戏中的位置信息是可以接受的)。 该API是RTCPeerConnection的扩展,如下所示:

 const dc = pc.createDataChannel("some label string"); // ,    – ,   – //    send dc.send("some string"); //    otherPc.addEventListener('datachannel', e => { const channel = e.channel; channel.onmessage = event => { console.log('received', event.data); }); }); 

在WebRTC官方样本页面上,有发送字符串二进制数据的示例。

DataChannel使用SCTP 。 它与RTP传输并行处理音频和视频流。 与音频和视频流通常使用的UDP不同,SCTP提供了许多其他功能,例如通过单个连接的多路复用通道或可靠,部分可靠(即可靠但无序)和不可靠的模式。

Google于2012年推出了QUIC(有关协议历史记录及其细微差别的更多信息,请参见我们的其他材料 -译者注)。 像WebRTC一样,QUIC协议也已在IETF的支持下采用,现在为HTTP / 3 。 QUIC具有许多重大创新,例如:减少延迟,基于拥塞控制的带宽计算,直接延迟校正(FEC)以及在用户空间(而非内核)中的实现以实现更快滚动。

QUIC可以替代WebRTC的RTCP,例如DataChannel的传输。 当前的实验试图通过使用单独版本的ICE传输来避免使用RTCPeerConnection API( 和SDP! )。 将其视为虚拟连接,可以增加安全性和NAT遍历

在下面的视频中,Chrome网络团队的Ian Swett解释了这个概念。 尽管此演讲已有多年历史,但仍提供有关该主题的其他信息:


QUIC的第一步


幸运的是, 2015年文章中的大多数代码仍然适用,并且可以轻松适应新的API。 让我们弄清楚。

从这里克隆代码或在这里尝试。 请注意,Chrome(必须为73+版本,现在是Canary版本)必须运行特殊标志才能在本地运行该实验:

 google-chrome-unstable --enable-blink-features=RTCQuicTransport,RTCIceTransportExtension 

ICE传输设置


RTCIceTransport规范基于ORTC,因此其设置类似于旧代码:

 const ice1 = new RTCIceTransport(); ice1.onstatechange = function() { console.log('ICE transport 1 state change', ice1.state); }; const ice2 = new RTCIceTransport(); ice2.onstatechange = function() { console.log('ICE transport 2 state change', ice2.state); }; //  ICE- ice1.onicecandidate = function(evt) { console.log('1 -> 2', evt.candidate); if (evt.candidate) { ice2.addRemoteCandidate(evt.candidate); } }; ice2.onicecandidate = function(evt) { console.log('2 -> 1', evt.candidate); if (evt.candidate) { ice1.addRemoteCandidate(evt.candidate); } }; //  ICE- ice1.start(ice2.getLocalParameters(), 'controlling'); ice2.start(ice1.getLocalParameters(), 'controlled'); ice1.gather(iceOptions); ice2.gather(iceOptions); 

请注意,与ORTC不同,此API没有RTCIceGatherer。 因为我们已经拥有安装ICE传输所需的一切。

配置QUIC传输


 const quic1 = new RTCQuicTransport(ice1); quic1.onstatechange = function() { console.log('QUIC transport 1 state change', quic1.state); }; const quic2 = new RTCQuicTransport(ice2); quic2.onstatechange = function() { console.log('QUIC transport 2 state change', quic2.state); }; //     QUIC quic2.addEventListener('quicstream', (e) => { console.log('QUIC transport 2 got a stream', e.stream); receiveStream = e.stream; }); 

在这里,实验脱离了使用基于证书的身份验证的规范。 而是使用公共密钥, 如Google Developers帖子所述
RTCQuicTransport连接配置有API公钥。 我们目前不打算使用此API代替原始验证。 当QUIC开始在Chromium中支持此证书时,它将由远程证书信令代替以验证自签名证书。
到目前为止,一切都很好。

QUICStream用于发送和接收数据


使用QUICStream比WebRTC DataChannel有点棘手。 WHATWG工作组创建的Streams API( 请参阅有关MDN的详细信息 )已被接受,但尚未实现

我们仅在QUIC传输进入“已连接”状态后才创建sendStream在不同的状态下会导致错误:

 quic1.onstatechange = function() { console.log('QUIC transport 1 state change', quic1.state); if (quic1.state === 'connected' && !sendStream) { sendStream = quic1.createStream('webrtchacks'); //   createDataChannel. document.getElementById('sendButton').disabled = false; document.getElementById('dataChannelSend').disabled = false; } }; 

然后,将处理程序附加到“提交”按钮和输入字段:单击按钮后,来自输入字段的文本在Uint8Array中进行编码并写入流中:

 document.getElementById('sendButton').onclick = () => { const rawData = document.getElementById('dataChannelSend').value; document.getElementById('dataChannelSend').value = ''; //  Uint8Array. ,       TextEncoder. const data = encoder.encode(rawData); sendStream.write({ data, }); }; 

第一个条目将触发远程QUIC传输上的onquicstream事件:

 //     QUIC quic2.addEventListener('quicstream', (e) => { console.log('QUIC transport 2 got a stream', e.stream); receiveStream = e.stream; receiveStream.waitForReadable(1) .then(ondata); }); 

...然后我们等待数据可读:
 function ondata() { const buffer = new Uint8Array(receiveStream.readBufferedAmount); const res = receiveStream.readInto(buffer); const data = decoder.decode(buffer); document.getElementById('dataChannelReceive').value = data; receiveStream.waitForReadable(1) .then(ondata); } 

来自receiveStream所有数据将被读取,解码为文本并放置在输出字段中。 因此,每次出现可读数据时。

结论与评论


我希望这个例子比Google博客上的类似例子更容易理解。 这种方法几乎不适合P2P连接,SCTP上的DataChannel已经对它们很好。 但是,这可能是另一端使用QUIC服务器的Web套接字的有趣替代方案。 在此之前,您应该确定一种使用不可靠且混乱的渠道的不错方法。 我认为,上述文章中的建议看起来更像是骇客,而不是决策。

还不清楚开发人员正在等待外界的反馈。 “已经介绍了规范,而不是再次雕刻快捷方式,而这些快捷方式将在我们身上保留数年,”听起来太明显了。 另外,社区的普遍意见倾向于使用WHATWG流,这使开发人员感到奇怪,他们要求测试自己的API来读取数据。

我还希望Chromium中的SCTP具有其他功能。 例如, 关于DataChannel的查询 -顺便说一句,评分最高-三年来几乎没有触及。 目前尚不清楚,当仍有SCTP任务时,为什么要重点关注QUIC。 但是,这不应阻止任何人测试QUIC和结果反馈。

Voximplant的评论


告诉我们前端irbisadm
长期以来,我们的SDK已用于向网络套接字发送信号。 这是一个出色的,经过时间考验的标准,但是存在一些问题。 第一个是TCP。 TCP在移动网络上不是那么好和快速,而且它不支持网络之间的漫游。 其次,它通常是文本形式的(也有二进制模式,但是您很少看到它)。

我们最近在DataChannel上启动了信号协议的封闭beta测试。 该协议也不是没有缺点,但是由于它可以在较差的网络中工作并且在漫游时可以一见钟情。 您更改过网络吗? 无需重新创建连接。 在大多数情况下, ICE Restart将有助于找到一种新的通信方式。 但是,正如我所说,该协议仍然存在缺陷:并非所有浏览器都支持所有协议扩展,例如保证交付和数据包顺序支持; 协议也不支持开箱即用的文本模式的gzip。 但是所有这些问题都可以在应用程序端解决。

Source: https://habr.com/ru/post/zh-CN441168/


All Articles