通信、ゲーム、ファイル転送のために 2 つのブラウザ間でデータを送信することは、かなり複雑なプロセスになる可能性があります。データを中継するサーバーをセットアップして料金を支払う必要があり、場合によってはこれを複数のデータセンターにスケーリングする必要があります。このシナリオでは、レイテンシが高くなる可能性があり、データのプライバシーを維持することが困難です。
これらの問題は、WebRTC の RTCDataChannel
API を使用してピア間でデータを直接転送することで軽減できます。この記事では、データ チャネルを設定して使用する基本的な方法と、現在のウェブでの一般的なユースケースについて説明します。
別のデータチャネルを使用する理由
WebSocket、AJAX、サーバー送信イベントがあります。別のコミュニケーション チャネルが必要な理由WebSocket は双方向ですが、これらすべてのテクノロジーはサーバーとの通信用に設計されています。
RTCDataChannel
は別のアプローチを取ります。
- ピアツーピア接続を可能にする
RTCPeerConnection
API と連携して動作します。これにより、中間サーバーがなく、「ホップ」が減少し、レイテンシを短縮できます。 RTCDataChannel
は、ストリーム制御伝送プロトコル(SCTP)を使用して、構成可能な配信セマンティクス(順不同の配信と再送信の設定)を可能にします。
RTCDataChannel
は現在、SCTP に対応しており、パソコンおよび Android の Google Chrome、Opera、Firefox でご利用いただけます。
注意点: シグナリング、STUN、TURN
WebRTC はピアツーピア通信を可能にしますが、ピア接続をブートストラップするためにメディアとネットワーク メタデータを交換するためにシグナリングが引き続きサーバーを必要とします。
WebRTC は NAT やファイアウォールに以下に対応しています。
- ICE フレームワーク: ピア間の最適なネットワーク パスを確立します。
- STUN サーバー: 各ピアの一般公開された IP とポートを確認します。
- TURN サーバー: 直接接続に失敗し、データ中継が必要な場合。
WebRTC がサーバーと連携してシグナリングとネットワーキングを行う仕組みについて詳しくは、実際の WebRTC: STUN、TURN、シグナリングをご覧ください。
機能
RTCDataChannel
API は、柔軟なデータ型をサポートしています。この API は WebSocket を厳密に模倣するように設計されており、RTCDataChannel
は文字列のほか、Blob、ArrayBuffer、ArrayBufferView などの JavaScript のバイナリ型をサポートしています。これらのタイプは、ファイル転送やマルチプレーヤー ゲームで作業する場合に役立ちます。
RTCDataChannel
は、信頼性が低く順序付けされていないモード(User Datagram Protocol(UDP)に類似)、信頼性の高い順序付きモード(伝送制御プロトコル(TCP)に類似)、部分的信頼性のあるモードで動作します。
- 信頼性の高い順序付けされたモードでは、メッセージの送信と配信順序が保証されます。これにより余分なオーバーヘッドがかかるため、このモードが遅くなる可能性があります。
- 信頼性が低く順序付けられていないモードは、すべてのメッセージが相手側に到着することや、どのような順序で到着するかが保証されるわけではありません。これによりオーバーヘッドが軽減され、このモードの動作がはるかに速くなります。
- 部分的信頼性モードでは、再送信のタイムアウトや再送の最大量などの特定の条件下でのメッセージの送信を保証します。メッセージの順序も構成できます。
最初の 2 つのモードで、パケットロスがない場合のパフォーマンスはほぼ同じです。ただし、信頼性が高く順序付けされたモードでは、パケットが失われると、そのパケットの背後で他のパケットがブロックされ、失われたパケットは再送信されて到着するまでに古くなっている可能性があります。もちろん、同じアプリ内で複数のデータ チャネルを使用して、それぞれに信頼性の高い、または信頼性の低いセマンティクスを持つこともできます。
以下は、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
オプション(失敗するまでの試行回数)を追加することもできますが、maxRetransfers または 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
:negotiated
をtrue
に設定した場合にのみ使用できる、チャンネルの独自の ID を指定できます。
ほとんどのユーザーが使用する必要があるオプションは、最初の ordered
、maxPacketLifeTime
、maxRetransmits
の 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 ファイル共有は、複数のクライアントに接続して迅速な共有が可能になることから、ウェブにとって有力な候補となっています。
移行を正常に行うには、いくつかの手順が必要です。
- File API を使用して JavaScript でファイルを読み取る。
RTCPeerConnection
を使用してクライアント間でピア接続を確立します。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();
};
この手法は、PubShare や GitHub のファイル共有アプリで使用されています。どちらもオープンソースであり、RTCDataChannel
ベースのファイル共有アプリの優れた基盤となります。
どうすればよいでしょうか。
RTCDataChannel
は、ファイル共有、マルチプレーヤー型ゲーム、コンテンツ配信向けのアプリを構築する新しい方法への扉を開きます。
- 前述のようなピアツーピアのファイル共有
- Mozilla の BananaBread に見られるように、WebGL などの他のテクノロジーと組み合わせたマルチプレーヤー ゲーム
- ピアツーピア データ通信を通じてウェブアセットを配信するフレームワークである PeerCDN を考案したコンテンツ配信
アプリの開発方法を変える
RTCDataChannel
による高パフォーマンス、低レイテンシの接続を使用することで、より魅力的なアプリを提供できるようになりました。PeerJS や PubNub WebRTC SDK などのフレームワークを使用すると、RTCDataChannel
の実装が簡単になり、API はプラットフォームをまたいで幅広くサポートされるようになりました。
RTCDataChannel
の登場により、ブラウザでのデータ転送に対する考え方が変わりました。