前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >QUIC DataChannels的第一步

QUIC DataChannels的第一步

作者头像
LiveVideoStack
发布2021-09-01 16:51:41
1.4K0
发布2021-09-01 16:51:41
举报
文章被收录于专栏:音视频技术音视频技术

对于WebRTC,QUIC协议可能提供SCTP之外的替代方案作为DataChannel的传输方式,本文通过示例测试的方式将该方法与WebRTC DataChannels进行了比较。LiveVideoStack对文章内容进行了翻译。感谢bilibili高级工程师王盛提供的审校支持。

文 / Philipp Hancke

译 / 元宝,咪宝

审校 / 王盛

原文 https://webrtchacks.com/first-steps-with-quic-datachannel/

基于QUIC的DataChannels现在被视为基于SCTP传输的替代方案。谷歌的WebRTC工作人员正在对其进行实验:

我们来做一个简单的单页示例测试一下,类似于传输文本的WebRTC数据通道示例(https://webrtc.github.io/samples/src/content/datachannel/basic/)。它提供了一个完整的工作示例,不涉及信令服务器,还允许更容易地将该方法与WebRTC DataChannels进行比较。

在看实际代码之前,首先让我们回顾一下DataChannel的一些基础知识。

快速回顾DataChannel

WebRTC中的DataChannel允许在对等点之间交换任意数据。它们既可以是可靠的,对于文件传输之类的事情非常有用,也可以是不可靠的,例如可以用于在游戏中交换位置信息。这个API是WebRTC里RTCPeerConnection的扩展,如下图所示:

代码语言:javascript
复制
const dc = pc.createDataChannel("some label string");
// wait for this to be open, e.g. by adding an event listener, then call send
dc.send("some string");

// on the other side
otherPc.addEventListener('datachannel', e => {
  const channel = e.channel;
  channel.onmessage = event => {
    console.log('received', event.data);
  });
});

WebRTC示例页面提供了一些用于发送简单字符串(https://webrtc.github.io/samples/src/content/datachannel/basic/)以及二进制数据(如arraybuffers)的示例。

(https://webrtc.github.io/samples/src/content/datachannel/datatransfer/)

DataChannel使用一种称为SCTP的协议。它与用于语音和视频流的基于RTP的传输并行运行。与通常使用UDP传输语音和视频流不同,SCTP提供各种特性,例如在同一连接上多路复用多个信道,以及提供可靠、部分可靠(即可靠但无序)和不可靠的模式。

谷歌在2012年推出了QUIC。就像它对WebRTC的做法一样,它后来把QUIC带到了IETF,现在是HTTP/3,QUIC提供了许多出色的功能,包括减少延迟、基于带宽估计的拥塞控制、前向纠错(FEC)以及在用户空间比内核中实现更快的部署周期。

对于WebRTC,QUIC协议可能提供SCTP之外的替代方案作为DataChannel的传输方式。此外,当前的实验还试图避免使用RTCPeerConnection API(和SDP!(https://webrtchacks.com/webrtc-sdp-inaki-baz-castillo/)),使用独立版本的ICE传输。我们可以把它想象成一个虚拟连接,它增加了一些安全性和一堆的NAT遍历(https://webrtchacks.com/stun-helps-webrtc-traverse-nats/)。

下面这段来自WebRTC Boston的视频是Chrome网络团队的Ian Swett关于这个话题的介绍,这段视频已经有几年的历史了,但是它提供了一些额外的背景知识:

视频网址:https://youtu.be/mIvyOFu1c1Q

QUIC的第一步

幸运的是, 2015年发布的“使用ORTC的第一步”(https://webrtchacks.com/first-steps-ortc/)文章中的大部分代码仍然是具有相关性的,并且可以快速适应这个新的API。

复制代码(https://github.com/webrtchacks/first-steps-ortc)或尝试一下(https://webrtchacks.github.io/first-steps-ortc/quic.html)。请注意,需要使用特殊的标志来启动Chrome(当前为Canary的73+)才能在本地进行实验:

代码语言:javascript
复制
google-chrome-unstable --enable-blink-features=RTCQuicTransport,RTCIceTransportExtension

设置ICE传输

这个RTCIceTransport 规范(https://github.com/w3c/webrtc-ice)是以ORTC为模型的,因此建立ICE transport与我们已有的旧代码非常相似:

代码语言:javascript
复制
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);
};
// Exchange ICE candidates.
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);
    }
};

// Start the ICE transports.
ice1.start(ice2.getLocalParameters(), 'controlling');
ice2.start(ice1.getLocalParameters(), 'controlled');
ice1.gather(iceOptions);
ice2.gather(iceOptions);

与ORTC不同,这个API没有 RTCIceGatherer 。这已足够以建立ICE传输了。

设置QUIC传输

代码语言:javascript
复制
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);
};

// Add an event listener for the QUIC stream.
quic2.addEventListener('quicstream', (e) => {
    console.log('QUIC transport 2 got a stream', e.stream);
    receiveStream = e.stream;
});

在这一点上,实验偏离了使用证书指纹的规范(https://w3c.github.io/webrtc-quic/)。相反,在原始博客文章的注释中指出了PSK密钥:

注意:RTCQuicTransport连接使用PSK密钥API进行设置。我们目前不打算将此API保留在原始审判之前。一旦将此支持添加到Chromium中的QUIC,它将被信令远程证书指纹替换,以验证握手中使用的自签名证书。

到现在为止还挺好的。

使用QUICStream发送和接收数据

使用QUICStream比使用WebRTC DataChannel稍微要复杂一点。WHATWG流API(请在MDN上阅读更多关于它的信息(https://developer.mozilla.org/en-US/docs/Web/API/Streams_API))被考虑过,但没有实现(https://github.com/w3c/webrtc-quic/issues/2)。

我们在QUIC传输连接起来时才创建 sendStream,因为它在此之前会出错:

代码语言:javascript
复制
quic1.onstatechange = function() {
  console.log('QUIC transport 1 state change', quic1.state);
  if (quic1.state === 'connected' && !sendStream) {
    sendStream = quic1.createStream('webrtchacks'); // similar to createDataChannel.
    document.getElementById('sendButton').disabled = false;
    document.getElementById('dataChannelSend').disabled = false;
  }
};

并启用发送按钮和输入文本区域。单击发送按钮后,文本将从文本区域中抓取,以Uint8Array编码写入sendStream中:

代码语言:javascript
复制
document.getElementById('sendButton').onclick = () => {
    const rawData = document.getElementById('dataChannelSend').value;
    document.getElementById('dataChannelSend').value = '';
    // we need a Uint8Array. Fortunately text is easy to convert using TextEncoder.
    const data = encoder.encode(rawData);
    sendStream.write({
        data,
    });
};

第一次写入将触发远程QUICTransport上的onquicstream事件:

代码语言:javascript
复制
// Add an event listener for the QUIC stream.
quic2.addEventListener('quicstream', (e) => {
    console.log('QUIC transport 2 got a stream', e.stream);
    receiveStream = e.stream;
    receiveStream.waitForReadable(1)
        .then(ondata);
});

我们将等待数据可以读取:

代码语言:javascript
复制
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博客文章中(https://developers.google.com/web/updates/2019/01/rtcquictransport-api)提供的示例更容易理解和修改。客户端到客户端的连接很难成为这里的主要用例——基于SCTP的DataChannel已经很好地介绍了这一点。但是,这可能成为WebSockets的另一种有趣的替代方案,在另一端使用基于QUIC的服务器。在此之前,需要定义一种表示不可靠和无序通道的好方法。在我看来,博客文章中的建议非常像黑客。

除此之外,我还不清楚团队正在寻找什么样的外部反馈。“实施规范而不是再次采取持续多年的捷径”是相当明显的。此外,社区团体现在的共识似乎是使用WHATWG流,这使得开发人员测试自己开发的API来处理读取变得更加奇怪。

我也希望Chromium的SCTP能有一些额外的功能。例如,这个DataChannel请求最高级的Chromium原生问题为什么在三年内几乎没有改变。我不太明白为什么在SCTP上有工作要做的时候,要关注QUIC,但这不应该阻止任何人测试QUIC并提供反馈。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 LiveVideoStack 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档