在两个浏览器之间发送数据以进行通信、游戏或文件传输可能是一个相当复杂的过程。它需要设置服务器并付费来中继数据,可能还需要将此服务器扩展到多个数据中心。在这种情况下,可能会出现高延迟,并且难以确保数据私密性。
使用 WebRTC 的 RTCDataChannel API 直接在对等方之间传输数据可以缓解这些问题。本文介绍了如何设置和使用数据通道的基础知识,以及目前网络上的常见用例。
为什么需要其他数据渠道?
我们有 WebSocket、AJAX 和 Server Sent Events。为什么我们需要其他沟通渠道?WebSocket 是双向的,但所有这些技术都是为与服务器之间的通信而设计的。
RTCDataChannel 采用不同的方法:
- 它与
RTCPeerConnectionAPI 搭配使用,可实现对等连接。这可以缩短延迟时间,因为没有中间服务器,跳数也更少。 RTCDataChannel使用流控制传输协议 (SCTP),允许配置交付语义(无序交付和重新传输配置)。
RTCDataChannel 现已在 Google Chrome、Opera 和 Firefox 中提供,支持桌面设备和 Android 设备上的 SCTP。
注意事项:信令、STUN 和 TURN
WebRTC 支持点对点通信,但仍需要服务器进行信令,以交换媒体和网络元数据来引导对等连接。
WebRTC 通过以下方式应对 NAT 和防火墙:
如需详细了解 WebRTC 如何与服务器配合使用以实现信令和网络连接,请参阅现实场景中的 WebRTC:STUN、TURN 和信令。
功能
RTCDataChannel API 支持灵活的数据类型集。该 API 旨在完全模仿 WebSocket,并且 RTCDataChannel 支持字符串以及 JavaScript 中的一些二进制类型,例如 Blob、ArrayBuffer 和 ArrayBufferView。在处理文件传输和多人游戏时,这些类型会很有用。
RTCDataChannel 可以采用不可靠且无序的模式(类似于用户数据报协议或 UDP)、可靠且有序的模式(类似于传输控制协议或 TCP)以及部分可靠的模式:
- 可靠且有序的模式可保证消息的传输以及消息的传送顺序。这会增加额外的开销,因此可能会使此模式变慢。
- 不可靠且无序的模式无法保证每条消息都能到达另一端,也无法保证消息到达另一端的顺序。这样可以减少开销,使此模式能够更快地运行。
- 部分可靠模式可保证在特定条件下(例如重传超时或最大重传次数)传输消息。消息的排序也是可配置的。
在没有丢包的情况下,前两种模式的性能大致相同。不过,在可靠且有序的模式下,丢失的数据包会导致其他数据包被阻塞在其后面,并且丢失的数据包在重新传输并到达时可能已过时。当然,您可以在同一应用中使用多个数据通道,每个通道都有自己的可靠或不可靠语义。
以下是 Ilya Grigorik 的《High Performance Browser Networking》一书中提供的一个实用表格:
| TCP | UDP | SCTP | |
| 可靠性 | 可靠 | 不可靠 | 可配置 |
| 外送 | 已订购 | 无序 | 可配置 |
| 传播 | 面向字节 | 面向消息 | 面向消息 |
| 流控制 | 是 | 否 | 是 |
| 拥塞控制 | 是 | 否 | 是 |
接下来,您将了解如何配置 RTCDataChannel 以使用可靠且有序的模式或不可靠且无序的模式。
配置数据渠道
网上有几个简单的 RTCDataChannel 演示:
在这些示例中,浏览器会与自身建立对等连接,然后创建数据通道并通过该对等连接发送消息。然后,它会创建一个数据通道,并通过对等连接发送消息。最后,您的消息会显示在页面另一侧的方框中!
开始使用此功能的代码非常简短:
const peerConnection = new RTCPeerConnection();
// Establish your peer connection using your signaling channel here
const dataChannel =
peerConnection.createDataChannel("myLabel", dataChannelOptions);
dataChannel.onerror = (error) => {
console.log("Data Channel Error:", error);
};
dataChannel.onmessage = (event) => {
console.log("Got Data Channel Message:", event.data);
};
dataChannel.onopen = () => {
dataChannel.send("Hello World!");
};
dataChannel.onclose = () => {
console.log("The Data Channel is Closed");
};
dataChannel 对象是从已建立的对等连接创建的。可以在信令发生之前或之后创建。然后,您传入一个标签来区分此渠道与其他渠道,以及一组可选的配置设置:
const dataChannelOptions = {
ordered: false, // do not guarantee order
maxPacketLifeTime: 3000, // in milliseconds
};
您还可以添加 maxRetransmits 选项(失败前尝试的次数),但只能指定 maxRetransmits 或 maxPacketLifeTime,而不能同时指定这两个选项。对于 UDP 语义,请将 maxRetransmits 设置为 0,并将 ordered 设置为 false。如需了解详情,请参阅以下 IETF RFC:Stream Control Transmission Protocol 和 Stream Control Transmission Protocol Partial Reliability Extension。
ordered:数据通道是否应保证顺序maxPacketLifeTime:尝试重新传输失败消息的最长时间maxRetransmits:尝试重新传输失败消息的最大次数protocol:允许使用子协议,该子协议可向应用提供元信息negotiated:如果设置为 true,则会移除在另一对等方上自动设置数据通道的操作,从而让您能够以自己的方式在另一对等方上创建具有相同 ID 的数据通道id:允许您为渠道提供自己的 ID,该 ID 只能与设置为true的negotiated结合使用)
大多数人只需要使用前三个选项:ordered、maxPacketLifeTime 和 maxRetransmits。借助 SCTP(现在所有支持 WebRTC 的浏览器都使用该协议),可靠且有序的传送默认处于启用状态。如果您想从应用层进行完全控制,使用不可靠且无序的传输方式是有意义的,但在大多数情况下,部分可靠性是有帮助的。
请注意,与 WebSocket 一样,RTCDataChannel 会在连接建立、关闭或出错时以及从对等方收到消息时触发事件。
这样做安全吗?
对于所有 WebRTC 组件而言,加密是必需的。借助 RTCDataChannel,所有数据都会通过数据报传输层安全协议 (DTLS) 进行保护。DTLS 是 SSL 的衍生版本,这意味着您的数据将与使用任何基于标准 SSL 的连接一样安全。DTLS 已标准化,并内置于所有支持 WebRTC 的浏览器中。如需了解详情,请参阅 Wireshark Wiki。
转变您对数据的看法
处理大量数据是 JavaScript 中的一个痛点。正如 Sharefest 的开发者所指出的那样,这需要以一种新的方式来考虑数据。如果您要传输的文件大于可用内存量,则必须考虑以新方式保存此信息。接下来,您将看到 FileSystem API 等技术如何发挥作用。
构建文件共享应用
现在,您可以使用 RTCDataChannel 创建可在浏览器中共享文件的 Web 应用。基于 RTCDataChannel 构建意味着传输的文件数据已加密,不会触及应用提供商的服务器。此功能与可连接到多个客户端以实现更快共享的功能相结合,使 WebRTC 文件共享成为 Web 的有力竞争者。
您需要完成以下几个步骤才能成功转移:
- 使用 File API 在 JavaScript 中读取文件。
- 使用
RTCPeerConnection在客户端之间建立对等连接。 - 使用
RTCDataChannel在客户端之间创建数据通道。
尝试通过 RTCDataChannel 发送文件时,需要考虑以下几点:
- 文件大小:如果文件大小合理,可以存储并加载为单个 Blob,则可以使用 File API 加载到内存中,然后通过可靠的渠道按原样发送文件(但请注意,浏览器对最大传输大小有限制)。随着文件大小的增加,情况会变得更加复杂。当需要分块机制时,系统会加载文件块并将其发送给另一个对等方,同时附带
chunkID元数据,以便对等方能够识别这些文件块。请注意,在这种情况下,您还需要先将块保存到离线存储空间(例如,使用 FileSystem API),只有在获得完整的文件后,才能将其保存到用户的磁盘。 - 数据块大小:这是应用的最小数据“原子”。由于目前存在发送大小限制(不过此问题将在未来版本的数据通道中得到修复),因此需要进行分块。目前建议的最大块大小为 64KiB。
文件完全转移到另一端后,可以使用锚标记下载:
function saveFile(blob) {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'File Name';
link.click();
};
PubShare 和 GitHub 上的这些文件共享应用就使用了此技术。它们都是开源的,可为基于 RTCDataChannel 的文件共享应用提供良好的基础。
那么,您可以做些什么呢?
RTCDataChannel 为构建用于文件共享、多人游戏和内容交付的应用开辟了新途径。
- 如前所述的点对点文件共享
- 多人游戏,与 WebGL 等其他技术搭配使用,如 Mozilla 的 BananaBread 中所示
- PeerCDN 是一种通过对等数据通信来分发 Web 资产的框架,它重新定义了内容分发
改变应用构建方式
现在,您可以通过 RTCDataChannel 使用高性能、低延迟的连接来提供更具吸引力的应用。借助 PeerJS 和 PubNub WebRTC SDK 等框架,RTCDataChannel 的实现变得更加简单,并且该 API 现在已获得广泛的平台支持。
RTCDataChannel 的出现可能会改变您对浏览器中数据传输的看法。