WebRTC データ チャネルを使用してブラウザ間でデータを送信する

通信、ゲーム、ファイル転送のために 2 つのブラウザ間でデータを送信することは、かなり複雑なプロセスになる可能性があります。データを中継するサーバーをセットアップして料金を支払う必要があり、場合によってはこれを複数のデータセンターにスケーリングする必要があります。このシナリオでは、レイテンシが高くなる可能性があり、データのプライバシーを維持することが困難です。

これらの問題は、WebRTC の RTCDataChannel API を使用してピア間でデータを直接転送することで軽減できます。この記事では、データ チャネルを設定して使用する基本的な方法と、現在のウェブでの一般的なユースケースについて説明します。

別のデータチャネルを使用する理由

WebSocketAJAXサーバー送信イベントがあります。別のコミュニケーション チャネルが必要な理由WebSocket は双方向ですが、これらすべてのテクノロジーはサーバーとの通信用に設計されています。

RTCDataChannel は別のアプローチを取ります。

  • ピアツーピア接続を可能にする RTCPeerConnection API と連携して動作します。これにより、中間サーバーがなく、「ホップ」が減少し、レイテンシを短縮できます。
  • RTCDataChannel は、ストリーム制御伝送プロトコル(SCTP)を使用して、構成可能な配信セマンティクス(順不同の配信と再送信の設定)を可能にします。

RTCDataChannel は現在、SCTP に対応しており、パソコンおよび Android の Google Chrome、Opera、Firefox でご利用いただけます。

注意点: シグナリング、STUN、TURN

WebRTC はピアツーピア通信を可能にしますが、ピア接続をブートストラップするためにメディアとネットワーク メタデータを交換するためにシグナリングが引き続きサーバーを必要とします。

WebRTC は NAT やファイアウォールに以下に対応しています。

WebRTC がサーバーと連携してシグナリングとネットワーキングを行う仕組みについて詳しくは、実際の WebRTC: STUN、TURN、シグナリングをご覧ください。

機能

RTCDataChannel API は、柔軟なデータ型をサポートしています。この API は WebSocket を厳密に模倣するように設計されており、RTCDataChannel文字列のほか、BlobArrayBufferArrayBufferView などの JavaScript のバイナリ型をサポートしています。これらのタイプは、ファイル転送やマルチプレーヤー ゲームで作業する場合に役立ちます。

RTCDataChannel は、信頼性が低く順序付けされていないモード(User Datagram Protocol(UDP)に類似)、信頼性の高い順序付きモード(伝送制御プロトコル(TCP)に類似)、部分的信頼性のあるモードで動作します。

  • 信頼性の高い順序付けされたモードでは、メッセージの送信と配信順序が保証されます。これにより余分なオーバーヘッドがかかるため、このモードが遅くなる可能性があります。
  • 信頼性が低く順序付けられていないモードは、すべてのメッセージが相手側に到着することや、どのような順序で到着するかが保証されるわけではありません。これによりオーバーヘッドが軽減され、このモードの動作がはるかに速くなります。
  • 部分的信頼性モードでは、再送信のタイムアウトや再送の最大量などの特定の条件下でのメッセージの送信を保証します。メッセージの順序も構成できます。

最初の 2 つのモードで、パケットロスがない場合のパフォーマンスはほぼ同じです。ただし、信頼性が高く順序付けされたモードでは、パケットが失われると、そのパケットの背後で他のパケットがブロックされ、失われたパケットは再送信されて到着するまでに古くなっている可能性があります。もちろん、同じアプリ内で複数のデータ チャネルを使用して、それぞれに信頼性の高い、または信頼性の低いセマンティクスを持つこともできます。

以下は、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 オプション(失敗するまでの試行回数)を追加することもできますが、maxRetransfers または maxPacketLifeTime のいずれかのみを指定できます。UDP セマンティクスについては、maxRetransmits0 に、orderedfalse に設定します。詳しくは、IETF RFC の Stream Control Transmission ProtocolStream Control Transmission Protocol Partial Reliability Extension をご覧ください。

  • ordered: データチャネルで順序を保証するかどうか
  • maxPacketLifeTime: 失敗したメッセージを再送信するための最大時間
  • maxRetransmits: 失敗したメッセージの再送信を試行する最大回数
  • protocol: アプリに対するメタ情報を提供するサブプロトコルの使用を許可します。
  • negotiated: true に設定すると、もう一方のピアでデータチャネルの自動設定が削除され、同じ ID を持つデータチャネルを相手側で独自の方法で作成できるようになります。
  • id: negotiatedtrue に設定した場合にのみ使用できる、チャンネルの独自の ID を指定できます。

ほとんどのユーザーが使用する必要があるオプションは、最初の orderedmaxPacketLifeTimemaxRetransmits の 3 つだけです。SCTP(現在は WebRTC をサポートするすべてのブラウザで使用されています)では、信頼性と順序付けがデフォルトで true になっています。アプリレイヤから完全に制御したい場合は、信頼性が低く順序付けされていないものを使用するのが理にかなっていますが、ほとんどの場合は部分的な信頼性が有用です。

WebSocket と同様に、RTCDataChannel は、接続が確立されたとき、閉じたとき、またはエラーが発生したとき、および相手ピアからメッセージを受信したときにイベントを呼び出します。

それは安全?

暗号化はすべての WebRTC コンポーネントで必須です。RTCDataChannel を使用すると、すべてのデータが Datagram Transport Layer Security(DTLS)で保護されます。DTLS は SSL の派生物です。つまり、データは標準的な SSL ベースの接続を使用した場合と同程度に保護されます。DTLS は標準化されており、WebRTC をサポートするすべてのブラウザに組み込まれています。詳しくは、Wireshark Wiki をご覧ください。

データに対する考え方を変える

JavaScript では、大量のデータの処理が問題になることがあります。Sharefest のデベロッパーが指摘するように、そのためにはデータについて新たな観点で考える必要がありました。使用可能なメモリ量を超えるファイルを転送する場合は、この情報を保存する新しい方法を検討する必要があります。ここで役に立つのが、次に説明するように FileSystem API のようなテクノロジーです。

ファイル共有アプリを作成する

RTCDataChannel を使用して、ブラウザでファイルを共有できるウェブアプリを作成できるようになりました。RTCDataChannel 上にビルドすると、転送されたファイルデータが暗号化され、アプリ プロバイダのサーバーには影響しなくなります。WebRTC ファイル共有は、複数のクライアントに接続して迅速な共有が可能になることから、ウェブにとって有力な候補となっています。

移行を正常に行うには、いくつかの手順が必要です。

  1. File API を使用して JavaScript でファイルを読み取る。
  2. RTCPeerConnection を使用してクライアント間でピア接続を確立します。
  3. RTCDataChannel を使用してクライアント間のデータチャネルを作成します。

RTCDataChannel 経由でファイルを送信する場合は、次の点を考慮してください。

  • ファイルサイズ: ファイルサイズが比較的小さく、1 つの Blob として格納および読み込める場合は、File API を使用してメモリに読み込み、信頼性の高いチャネル経由でファイルをそのまま送信できます(ただし、ブラウザでは最大転送サイズに制限があります)。ファイルサイズが大きくなるほど、処理は複雑になります。チャンク メカニズムが必要な場合、ファイル チャンクが読み込まれ、chunkID メタデータとともに別のピアに送信されます。これにより、ピアはチャンクを認識できるようになります。この場合、(FileSystem API などを使用して)最初にチャンクをオフライン ストレージに保存し、ファイル全体が揃う場合にのみユーザーのディスクに保存する必要があります。
  • チャンクサイズ: アプリのデータの最小の「アトム」です。現在、送信サイズには上限があるため、チャンクは必須です(これはデータチャネルの今後のバージョンで修正される予定です)。現時点で推奨される最大チャンクサイズは 64 KiB です。

ファイルが反対側に完全に転送されたら、アンカータグを使用してダウンロードできます。

function saveFile(blob) {
  const link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = 'File Name';
  link.click();
};

この手法は、PubShareGitHub のファイル共有アプリで使用されています。どちらもオープンソースであり、RTCDataChannel ベースのファイル共有アプリの優れた基盤となります。

どうすればよいでしょうか。

RTCDataChannel は、ファイル共有、マルチプレーヤー型ゲーム、コンテンツ配信向けのアプリを構築する新しい方法への扉を開きます。

  • 前述のようなピアツーピアのファイル共有
  • Mozilla の BananaBread に見られるように、WebGL などの他のテクノロジーと組み合わせたマルチプレーヤー ゲーム
  • ピアツーピア データ通信を通じてウェブアセットを配信するフレームワークである PeerCDN を考案したコンテンツ配信

アプリの開発方法を変える

RTCDataChannel による高パフォーマンス、低レイテンシの接続を使用することで、より魅力的なアプリを提供できるようになりました。PeerJSPubNub WebRTC SDK などのフレームワークを使用すると、RTCDataChannel の実装が簡単になり、API はプラットフォームをまたいで幅広くサポートされるようになりました。

RTCDataChannel の登場により、ブラウザでのデータ転送に対する考え方が変わりました。

補足説明