使用 WebRTC 数据通道在浏览器之间发送数据

出于通信、游戏或文件传输目的在两个浏览器之间发送数据可能相当复杂。它需要设置服务器并支付流量费用来中继数据,并且可能需要将其扩容到多个数据中心。在这种情况下,可能会出现较长的延迟时间,并且很难保持数据的私密性。

通过使用 WebRTC 的 RTCDataChannel API 将数据从一个对等设备直接传输到另一个对等设备,可以缓解这些问题。本文介绍了有关如何设置和使用数据渠道的基础知识,以及当今网络的常见用例。

为何要选择其他数据渠道?

我们有 WebSocketAJAX服务器发送事件。为什么需要其他沟通渠道?WebSocket 是双向的,但所有这些技术都设计用于与服务器相互通信。

RTCDataChannel 采用不同的方法:

  • 它与 RTCPeerConnection API 配合使用,后者可实现点对点连接。这样可以缩短延迟时间 - 没有中间服务器,“跃点”更少。
  • RTCDataChannel 使用流控制传输协议 (SCTP),允许可配置的传送语义无序传送和重新传输配置。

RTCDataChannel现在可通过桌面设备和 Android 设备的 Google Chrome、Opera 和 Firefox 支持 SCTP。

注意事项:信号、STUN 和 TURN

WebRTC 支持点对点通信,但它仍需要服务器来实现信令,以便交换媒体和网络元数据来引导对等连接。

WebRTC 可通过如下方式应对 NAT 和防火墙:

  • ICE 框架,用于在对等方之间建立尽可能最佳的网络路径。
  • STUN 服务器确定每个对等方的可公开访问的 IP 和端口。
  • 如果直接连接失败且需要进行数据中继,请更换服务器

如需详细了解 WebRTC 如何与服务器搭配使用以实现信号和网络,请参阅 WebRTC 实际应用:STUN、TURN 和 Signaling

功能

RTCDataChannel API 支持一组灵活的数据类型。该 API 旨在完全模拟 WebSocket,RTCDataChannel 支持 strings 以及 JavaScript 中的某些二进制类型,例如 BlobArrayBufferArrayBufferView。处理文件传输和多人游戏时,这些类型会很有用。

RTCDataChannel 可在不可靠且无序的模式(类似于用户数据报协议或 UDP)、可靠且有序的模式(类似于传输控制协议 (TCP))以及部分可靠模式下运行:

  • 可靠且有序的模式可保证消息的传输以及消息的传送顺序。这会产生额外的开销,因此可能会减慢此模式的速度。
  • 不可靠且无序模式并不保证每条消息都能发送到另一端,也不能保证消息以什么顺序到达。这样可以消除开销,使该模式的运行速度更快。
  • 部分可靠模式可保证消息在特定条件下传输,例如重新传输超时或最大重新传输次数。消息的顺序也可配置。

没有数据包丢失的情况下,前两种模式的性能大致相同。但在可靠且有序的模式下,丢失的数据包会导致其他数据包在其后面被屏蔽,并且丢失的数据包可能会在重新传输并到达时已过时。当然,可以在同一应用中使用多个数据通道,每个数据通道都有自己可靠或不可靠的语义。

下面是 Ilya Grigorik 创作的 High Performance Browser Networking 中的实用表:

TCPUDPSCTP
可靠性可靠不可靠可配置
送餐已下单无序可配置
传输面向字节以消息为导向以消息为导向
流控制
拥塞控制

接下来,您将学习如何配置 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:流控制传输协议流控制传输协议部分可靠性扩展

  • ordered:如果数据通道是否应保证顺序
  • maxPacketLifeTime:尝试重新传输失败消息的最长时间
  • maxRetransmits:尝试重新传输失败消息的次数上限
  • protocol:允许使用子协议,以便向应用提供元信息
  • negotiated:如果设置为 true,则移除另一个对等方上数据渠道的自动设置,提供您自己的方式在另一端创建具有相同 ID 的数据渠道
  • id:可让您为频道提供自己的 ID,该 ID 只能与设置为 truenegotiated 结合使用。

大多数人需要使用的唯一选项只有前三个:orderedmaxPacketLifeTimemaxRetransmits。使用 SCTP(现已由支持 WebRTC 的所有浏览器使用)时,默认情况下可靠且有序。如果您希望从应用层获得完全控制,可以使用不可靠且无序,但在大多数情况下,部分可靠性会很有帮助。

请注意,与 WebSocket 一样,RTCDataChannel 会在连接建立、关闭或发生错误时,以及从另一个对等端收到消息时触发事件。

这样做安全吗?

对于所有 WebRTC 组件而言,加密是必需的。借助 RTCDataChannel,所有数据都通过数据包传输层安全协议 (DTLS) 进行保护。DTLS 是 SSL 的衍生产品,这意味着您的数据将像使用任何基于 SSL 的标准连接一样安全。DTLS 已标准化并内置于支持 WebRTC 的所有浏览器中。有关详情,请参阅 Wireshark wiki

改变您看待数据的方式

处理大量数据可能是 JavaScript 中的一个痛点。正如 Sharefest 的开发者指出的那样,这需要以新的方式看待数据。如果您传输的文件大于可用内存量,则必须考虑新的方法来保存此信息。这正是 FileSystem API 等技术的用武之地,详见下文。

构建文件共享应用

您现在可以使用 RTCDataChannel 创建可在浏览器中共享文件的 Web 应用。基于 RTCDataChannel 构建意味着传输的文件数据会加密,并且不会接触应用提供商的服务器。该功能,再加上连接到多个客户端以实现更快共享的可能性,使得 WebRTC 文件共享成为 Web 的强大候选对象。

为确保成功转移,您需要完成以下几个步骤:

  1. 使用 File API 读取 JavaScript 中的文件。
  2. 使用 RTCPeerConnection 在客户端之间建立对等连接。
  3. 使用 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();
};

PubShareGitHub 上的这些文件共享应用就使用了这种方法。它们都是开源的,为基于 RTCDataChannel 的文件共享应用奠定了良好的基础。

那么您该怎么做呢?

RTCDataChannel 为构建文件共享、多人游戏和内容分发应用打开了大门。

  • 点对点文件共享(如前所述)
  • 多人游戏结合其他技术(例如 WebGL),如 Mozilla 的 BananaBread 中所述
  • PeerCDN 是一个通过点对点数据通信提供网络资源的框架

改变您构建应用的方式

您现在可以通过 RTCDataChannel 使用高性能、低延迟的连接,提供更具吸引力的应用。借助 PeerJSPubNub WebRTC SDK 等框架,RTCDataChannel 更易于实现,且该 API 现在可提供跨平台的广泛支持。

RTCDataChannel 的出现可能会改变您对于浏览器中的数据传输的看法。

了解详情