WebRTCのデータチャネル解説

データチャネルによって従来では成し得なかったP2Pのブラウザアプリケーションの実現が可能となります。WebRTCといえば、多くの人がブラウザ上での音声映像チャットを思い浮かべるでしょう。しかし、WebRTCではP2Pでのデータ通信を提供するデータチャネルも含んでいます。

この記事では、データチャネルの特徴とAPIやプロトコルについて解説し、最後にその活用方法に触れたいと思います。

なおこの記事は、WebRTCについてある程度理解が進んでいる方に向けて書かれています。WebRTC Advent Calendar 2014の1日目の記事である[WebRTCコトハジメ - Qiita](http://qiita.com/Tukimikage/items/286f569d110daede721e)が、この記事の理解の役に立つかもしれません。

## なぜデータチャネルか？

データチャネルは[WebRTC仕様](http://www.w3.org/TR/webrtc/)のピアコネクションに含まれており、ブラウザ間でリアルタイムにデータをやりとりする能力を提供します。旧来より、ブラウザ間でのデータの交換には種々のAJAXのテクニックやWebSocketが使われていました。それらを用いる場合では必ずデータがサーバを経由する一方で、データチャネルはブラウザ間のP2Pです。つまりデータチャネルは、最短の経路でデータを送信するためハイパフォーマンスですし、サーバに対する負荷が低いのでトラフィック耐性が高いと言えるでしょう。

## データチャネルにおける JavaScript の API

データチャネルの API は WebSocket を模倣して規定されました。つまり`onopen`、`onmessage`、`onclose`イベントにそれぞれハンドラを設定することによって動作を定義することができます。具体的には以下のようなコードによって、既存の音声映像チャットアプリケーションにデータ通信能力を追加することができます。（事前にサーバ経由でのオファーアンサーネゴシエーションが必要です。）

```js
// pc は既存のピアコネクションのインスタンス
var dataChannel = pc.createDataChannel("myLabel");

dataChannel.onmessage = function (event) {
  console.log("データチャネルメッセージ取得:", event.data);
};

dataChannel.onopen = function () {
  dataChannel.send("hello");
};

dataChannel.onclose = function () {
  console.log("データチャネルのクローズ");
};
```

上記の例では対向のピアに対してUTF-8でエンコードされた文字列を送信していますが、データチャネルではバイナリを送信することもできます。それらの例を以下に示します。

```js
// 生のテキスト情報をバイナリで送信

dataChannel.send(new Blob(["blobs String"], {type: "text/plain"}));
// ArrayBufferを送信
dataChannel.send(new ArrayBuffer(32));
// ArrayBufferViewを送信
dataChannel.send(new UInt8Array([1,2,3]));
```

また、データチャネルは柔軟な設定の能力を備えています。その設定は`createDataChannel`の第2引数に渡すオブジェクトによって定義され、ピア間のデータチャネル確立時に処理されます。主に用いられるプロパティは、メッセージの順序性の保証の有無をbool値で指定する`ordered`と、通信の信頼性を設定する`maxRetransmitTime`と`maxRetransmits`（これらは互いに排他）です。以下に信頼性を保証しない設定の例を示します。

```js
var dataChannelOptions = {
  ordered: false,          // 順序性を保証しない
  maxRetransmitTime: 3000, // 再送まで最大3000ミリ秒
};
````

値を指定しない場合では、高い信頼性を持つデフォルトの設定が用いられます。多くのアプリケーションではそのままで構いません。しかし、「君が私を撃った」というような致命的なインタラクションが必要なオンラインゲームや、地図上のピンのプロットのような位置情報を頻繁に送信するようなアプリケーションでは、その設定の変更が有効に働くことになるでしょう。

## データチャネルのプロトコル SCTP

データチャネルの高度な能力は、P2Pセッション上の新たなメッセージ指向のコネクションの追加によって実現されます。ここからは、そのために用いられているプロトコルについて説明します。

データチャネルは、メッセージ指向で多重ストリームの能力を持つプロトコルであるSCTPを採っています。SCTPは、電話網のシグナリングプロトコルである[SS7](http://ja.wikipedia.org/wiki/共通線信号No.7)をIP上で伝送するために規定されたプロトコルであり、既存のインターネット上でよく使われるプロトコルと比較して高度な機能を有しています。主な機能を以下に示します。

- 信頼性の柔軟な設定
- パケットの順序性の保証有無の設定
- SCTPアソシエーションと呼ばれるメッセージ送信・多重ストリーム
- フロー制御
- 輻輳制御

つまり、データチャネル上の便利な機能群はSCTPの機能をそっくりそのまま用いて実現しているのです。

### DTLS上のSCTP

さて、この便利なSCTPがインターネットの世界で日の目を浴びてこなかったのは何故でしょうか。それはNATの存在に起因しています。多くの家庭に設置されているブロードバンドルータなどのNATボックスは、自らが知るプロトコル以外を破棄してしまうことがほとんどです。それはインターネットの世界で、トランスポートにTCPとUDPしか利用することができないことを意味しています。

しかし、WebRTCではDTLS上のSCTPを実装することによってこの問題を解決してしましました。データチャネルのプロトコルスタックは以下の図のようになっています。

![data_chanel_protocol_stack.png](https://qiita-image-store.s3.amazonaws.com/0/10409/734933db-382c-48c3-c320-9f9816b201d4.png)

WebRTCのSCTPは、カーネルではなくユーザランド上のブラウザ上に実装されており、NATボックスからはUDPのパケットにしか見えません。このような構造によって、NAT越えを実現しつつ、セキュリティを担保しながら、現実的なSCTPの利用を可能にしてしまいました。

### SCTPのWebRTC用の拡張

WebRTCのSCTPはカーネル上の実装を使うのではなく、ブラウザ上であらためて実装されています。そして、WebRTCでSCTPを利用するためにいくつかの拡張が加えられています。ここからは、[draft-ietf-rtcweb-data-protocol](https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol)と[draft-ietf-rtcweb-data-channel](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel)で議論が進行している拡張について述べます。

SCTPのコネクションは「アソシエーション」と呼ばれ、メッセージの送信と多重ストリームの能力を提供します。SCTPのストリームは単一方向で16ビットのIDで識別されますが、データチャネルでは2つのストリームを併せて双方向のストリームで扱うよう規定しています。

SCTPで扱うストリームは、アソシエーション上のメッセージ交換によってシグナリングされ、WebRTCでのストリームの確立のために新たな「Data Channel Establishment Protocol」（DCEP）が規定されています。DCEPでは、`DATA_CHANNEL_OPEN`と`DATA_CHANNEL_ACK`の2つのタイプのメッセージが規定されています。以下に`DATA_CHANNEL_OPEN`に含まれるフィールドを示します。

![datachanel_feild.png](https://qiita-image-store.s3.amazonaws.com/0/10409/d94d4bf2-348d-d79e-4daa-4297346c5314.png)

Channel Typeのフィールドは要求する信頼性を示しており、下記のいずれかでなければなりません。

|Channel Type|信頼性|順序|
|:----------|:--|:--|
|DATA_CHANNEL_RELIABLE(0x00)|保証する|保証する|
|DATA_CHANNEL_RELIABLE_UNORDERED(0x80)|保証する|保証しない|
|DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT(0x01)|部分的に保証する（指定回数内の再送）|保証する|
|DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT_UNORDERED(0x81)|部分的に保証する（指定回数内の再送）|保証しない|
|DATA_CHANNEL_PARTIAL_RELIABLE_TIMED(0x02)|部分的に保証する（指定時間内の再送）|保証する|
|DATA_CHANNEL_PARTIAL_RELIABLE_TIMED_UNORDERED(0x82)|部分的に保証する（指定時間内の再送）|保証しない|

また、Priorityには、同一のSCTPコネクション上の他のチャネルに対する相対的な優先度を指定します。そしてLabelには、このチャネルに指定する任意ラベルを設定します。

イニシエータからの`DATA_CHANEL_OPEN`に対して、応答側は`DATA_CHANNEL_ACK`を返し、チャネルは開始します。そのフィールドは1バイトのChanel Typeのみです。

SCTPのメッセージにはプロトコル識別のための16ビットの数値である「Payload Protocol Identifer」（PPID）が定義されており、WebRTCのために新たな3つの拡張が規定されています。まず、その1つはこれまで説明したDCEPのための「WebRTC DCEP」が50に規定されています。残りはデータチャネル用で、1つはUTF-8の文字列向けに「WebRTC String」が50に、もう1つはJavaScriptのArrayBufferまたはBlobに用いるバイナリ送信用の「WebRTC Binary」が53に規定されています。

## データチャネルの活用方法

データチャネルには様々な活用方法が考えられます。

単純なケースでは、音声映像チャットアプリケーションでのオファーアンサーネゴシエーションに用いるというものがあります。WebRTCではブラウザからのマイクやカメラへのアクセスのために、ユーザに対する許諾を求めます。通常では、ユーザのブラウザに対する承認の動作が完了するまで、通信確立のためのオファーアンサーネゴシエーションは開始されません。つまり、ブラウザのICEによる候補アドレスの収集やホールパンチは、ユーザのインタラクションがあるまで試みることができません。しかし、あらかじめデータチャネルのコネクションを確立させておけば、ブラウザは利用者に対して秘密裏にその処理を終えてしまうことができます。（また、不可能な場合は利用者のインタラクションの前にそれを伝えることができます。）なぜならば、データチャネルの確立には利用者の承認を求めることはありませんし、WebRTCにおける多重化はUDP直上のDTLSで行われるため、ホールパンチするポートはたったひとつで再利用可能だからです。

他の有効な活用方法について、ここからは[7 Creative Uses of WebRTC's Data Channel](https://bloggeek.me/webrtc-data-channel-uses/)から紹介したいと思います。

### ファイル共有

データチャネルでは、P2Pでのバイナリの伝送能力を持っているので、高性能なファイル共有が可能です。旧来のWebSocketなどでは、サーバ経由で情報をやりとりしなければなりませんでしたが、これは、WebRTCに置き換えられるでしょう。

この機能は WebRTC だけでなく、HTML5 の File API と組み合わせて実現されるでしょう。

### CDN の補強

インターネット上のトラフィックの軽減やアクセス速度の向上のためにCDNが用いられていますが、近傍の同一リソースにアクセスするブラウザのキャッシュを同一の目的で利用するのも有効でしょう。従来はブラウザ間の通信の手段を持ちあわせていませんでしたが、WebRTCのデータチャネルによってその要件は満足します。このような取組みは既に始まっており、Yahooによる[Peer CDN](https://peercdn.com/)などがあります。

### ブラウザ版 Bit Torrent

巨大なリソースを複数のユーザで共有する Bit Torrent は有名なP2Pアプリケーションのひとつでしょう。データチャネルを用いれば、このようなアプリケーションだってブラウザ上で実行することができてしまいます。驚くべきことにその実装は既に始まっており[Web TORRENT](https://github.com/feross/webtorrent)として公開されています。

### 低遅延ネットワーク

もっとも、P2Pというだけでサーバ経由と比較して圧倒的な低遅延である恩恵が受けられます。これは、オンラインゲーマをブラウザの世界に呼び寄せるのに多大な貢献となるでしょう。

Mozillaによる[Banana Bread ](https://developer.mozilla.org/en/demos/detail/bananabread)は、一見するとWebGLを用いたFPSゲームのデモンストレーションですが、マルチプレイヤーモードでのユーザ間の通信にWebRTCのデータチャネルを利用しています。

### サーバレスネットワーク

WebRTCはその特性上、ブラウザ間のコネクションの確立にサーバ経由のネゴシエーションが少なくとも1度必要な為、真のサーバレスネットワークは今のところ実現出来ません。しかし、サービスを実行するために本当にWebサーバが必要なことはそれほど多くないかもしれません。アドホックな動的なネットワーク上でのデータの保持とアクセスは実現できるはずです。

そのような技術に分散ハッシュテーブルがあり、その実装のひとつであるChordのWebRTC版が[WebRTC-Chord](https://github.com/tsujio/webrtc-chord)として公開されています。

### TORの代替

TORは匿名性の高いネットワークを実現するサービスで、リクエストの委譲と透過を受け付ける複数のサーバから構築されます。これらのサーバを複数のブラウザが担うことによって、アドホックに生成された、高信頼で秘匿性の高いネットワークサービスが実現できるかもしれません。

### 高プライバシーなサーチエンジン

検索エンジンは、ユーザがリストから訪れるページを選択するまでの時間や履歴などの様々な情報を収集し、より良い検索結果を提示しようとしますが、これはプライバシの侵害とも言えるでしょう。[Blippex](https://www.blippex.org/)は、リクエストの匿名化のためにWebRTCのデータチャネルを利用し、他のブラウザに対して検索エンジンへのリクエストを委譲します。

## おわりに

以上、WebRTCのデータチャネルについて簡単に紹介しました。WebRTCのデータチャネルは音声映像チャットと比較して、ビジュアルのインパクトが少ないためかあまり着目されていないようにも見えます。しかし、P2Pデータを活用したアプリケーションの可能性は非常に大きく、様々なユースケースでの活用が期待されます。データチャネルのJavaScriptのAPIは非常に簡便であり、高機能なコネクションを容易に扱うことが可能ですので、様々なサービスが実現されることが期待できそうです。