2014年3月22日土曜日

P2P探訪 WebRTC用、SDP交換Peerを作ってみた。〜WebRTCで転送する〜

続きです。
WebRTCのPeerに、SDPデータを転送する機能を追加してみました。


WebRTCを用いてP2P通信を確立するには、SDPを交換する必要があるのでした。SDPの交換はWebRTCフレームワークで提供されていないので、自作する必要があったのでした。

今回は、WebRTCのPeerにSDPデータを交換する機能を実現してみました。
本機能によって、一度ネットワークに参加する事が出来たならば、サーバーを経由せずに、P2Pネットワークを成長させる事ができるようになります。


[仕組み]

WebSocketの場合とほとんど同じです。通信方法がWebSocketから、WebRTCのデータコネクションに変わるだけです。
仲介役のPeerが指定されたアドレス(uuid)のPeetへメッセージを送信する機能を実現するだけで良いでしょう。

例えば、以下のような感じで書けます。


function MessageTransferBase(target) {
 this.mParent = target;
        // 他のPeerからメッセージを受け取った
 MessageTransferBase.prototype.onReceiveMessage = function(caller,message) {
 };

        //仲介者(transfer)を経由して、メッセージを送信してもらう。
 MessageTransferBase.prototype._sendUnicastMessage = function(transfer, to, from, content) { 
  console.log("======sendUnicastMessage :");
  var mes = {};
  mes.messageType = "unicast";
  mes.to = to;
  mes.from = from;
  mes.content = content;
  this.mParent.getPeerList().get(transfer).caller.sendMessage(JSON.stringify(mes));
 }
        //仲介の依頼ならば、仲介してあげる。自分へのメッセージならば、受信する。
 MessageTransferBase.prototype.onTransferMessage = function(caller, message) {
     var p2pMes = JSON.parse(message);

      if("unicast" == p2pMes.messageType) {
       console.log("======onTransferMessage:");
       var mes = {};
       mes.to = p2pMes.to;
       mes.from = p2pMes.from;
       mes.content = p2pMes.content;
       mes.messageType = "transfer";
       var targetPeer = this.mParent.getPeerList().get(p2pMes.to).caller;
       targetPeer.sendMessage(JSON.stringify(mes));
      }
      else if("transfer" == p2pMes.messageType) {
       this.onReceiveMessage(caller, p2pMes);
      }
 }
}


https://github.com/kyorohiro/HelloWebRTC/blob/master/signalPeer/peer/messagetransferbase.js

[次回予告]

成果報告っぼくなってきているので、「今までの成果をノウハウとしてまとめる」。
数百〜数千のPeerがネットワーク上で、自己組織的にネットワークを構築して、データやPeerを検索する仕組の構築方法」。「Torrentベースの高速データ配信の導入」のどれか

2014年3月12日水曜日

P2P探訪 WebRTC用、SDP交換サーバーを作ってみた。〜WebSocketで転送する〜

続きです。
WebSocketを用いて、SDPデータを転送する機能を実現しました。


[コネクションを維持して任意のタイミングで通信]

通常、ブラウザーでサイトにアクセスする場合、ブラウザーは必要なデータをダウンロードすると、コネクションを切ります。

コネクションが切れてしまうと、サーバーからクライアントへメッセージを送信する事ができません。
なので、以前は、ホームページの表示完了後、少し時間がたってからサーバーから何かしらのPush通信を受けると行った事が出来ませんでした。

しかし、WebSocketが誕生しこの状況はいっぺんします。
WebSocketを使った場合、サーバーとクライアントのコネクションはクローズされず、維持し続けます。これによって、サーバーから、クライアントへメッセージを送信する事ができるようになりました。

WebSocketを使えば、任意のタイミングで、サーバーとブラウザーが通信できます。
この機能を利用すれば、容易にSDP交換サーバーの実現することができるでしょう。

[SDP交換サーバーの役目]


SDP交換サーバーの役目は、(a)Peerの存在を他のPeerへ伝える事。そして、(b)SDP情報を、Peer同士で交換できるようにする事です。

今回作成した、SDP交換サーバーでは、以下の機能を実装しました。
[1]  Peer全体にメッセージを送信する。
[2] 指定したUUIDのPeerへメッセージを送信する。


あたらに加わったPeerが、「[1]の機能」を用いて、p2pネットワーク全体にUUIDを送信すれば、「(a)の目的」を果たす事ができます。
また、P2P接続を確立したい場合、「[2]の機能」を用いて、他のPeerへ自身のSDPを送る事ができるでしょう。


[実装]

nodejsを使って実現しました。
https://github.com/kyorohiro/HelloWebRTC/blob/master/signalServer/signalserver.njs


    // httpサーバーを立ち上げる
    this.mHttpServer = HTTP.createServer(function (req, res) {
          ...
    }
    // websocketサーバーを立ち上げる
    this.mWsserverSocket = new WSServer({httpServer: this.mHttpServer});
    this.mWsserverSocket.on('request', function(req){
          ....
          ....
       // 受け取ったメッセージを解析して、転送する。  
       if(messageType === "unicast") {
       var v = {}
            v["_contentType"]    = contentType;
            v["_content"] = content;
            v["_to"]      = to;
            v["_from"]    = from;
           //[1] Peer全体にメッセージを送信する。
            _own.uniMessage(to, JSON.stringify(v));
       } else if(messageType =="broadcast") {
             var v = {}
             v["_contentType"] = contentType;
             v["_content"]     = content;
             v["_from"]        = from;
             //[2] 指定したUUIDのPeerへメッセージを送信する。
             _own.broadcastMessage(JSON.stringify(v));
       } 
    });


[次回]

続きを書きます。クライアント側の解説をもう少しします。それが終わったら、各Peerにもこの機能を持せたサンプルを提供します。
余裕があれば、それを土台に主だったDHTを、WebRTC上で実現できるか検証してみます。




2014年3月11日火曜日

P2P探訪 WebRTC用、SDP交換サーバーを作ってみた。〜 UUIDでPeerを識別する 〜

WebRTCを用いて、P2P通信をする場合には、SDPというデータを交換する必要がある事を説明しました。
ただし、このSDPを交換する部分はWebRTCでは提供されていません。自作する必要があるでしょう。※有り物を拝借するでも良いです。

試しに、WebSocketを使ってSignalServer(SDP交換機)を作成してみました。紹介します。


[UUIDでPeerを識別する]

多数のPeerの交換器としてサーバーを動作させたい場合、各Peerを識別する方法が必要です。
特にP2Pシステムでは、統制を取らずに一意の識別子の作成をする事が望ましいです。
※今は交換サーバーが一つを想定しているので、本来考慮する事ないかもしれません。

今回は乱数を使用して実現しました。128bitの値を乱数で生成します。0〜2**128の値衝突する確率は、1/2**64ととても少ないのです。
※ アレと思った方は、「誕生日攻撃」ググると良い

// ref http://note19.com/2007/05/27/javascript-guid-generator/
function s4() {
 return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}
function createUUID() {
 return s4()+s4()+"-"+s4()+"-"+s4()+"-"+s4()+"-"+s4()+s4()+s4();
}

※rfc4122では、最初の6bitは予約されています。


[次回]

続きを書く..。その続きは、Peerに交換機の機能を付けたサンプルを紹介する予定。


※ 成果物は以下
https://github.com/kyorohiro/HelloWebRTC/tree/master/signalServer






2014年3月1日土曜日

P2P探訪 StunでNat越え その7 WebRTCでShakehand

前回、Stunの実例として、WebRTCを利用してSDP(自身のアドレスとポート)を取得しました。せっかくなので、WebRTCを使って、Peer同士でメッセージのやり取してみましょう。


WebRTCを用いて、お互いのPeerが接続してメッセージを送る方法は簡単です。
1. 自分のSDPと相手のSDPを取得する。
2. 取得したSDPを設定する。
3. メッセージを送信する。※今回はテキスト

とするだけです。

[解説]

以前説明した通り、Peerどうしが接続するためには、接続相手のアドレスを知る必要があります。このアドレスを知りたい場合には、Stunサーバーを利用するのでした。

また、接続される側も、接続してくるPeerのアドレスがわかっていれば、「UDPパンチ」などを用いて、接続できる可能性をあげる事ができるのは、ご存知のことでしょう。以前解説したとおりです。

WebRTCも同様の手法を取っています。「接続される側」、「接続する側」のアドレスを前もって、WebRTCの知らせる事で、Peer同士が接続できるようになります。

※注意点
WebRTCでは、「接続される側」、「接続する側」のアドレスを、Peerに知らせる方法は提供されていません。
独自に実装する必要があります。WebSocketを利用する方法流行っているみたいです!!



[接続の処理の流れ]

実際の処理の流れを見てみましょう。接続が完了すれば、メッセージを送信できるようになります。

○自分のSDPを取得/設定
#接続を要求する側
O-1. RTCPeerConnectionを生成する。
O-2. RTCPeerConnection#createOffer()をコールする。
O-3. RTCPeerConnection#setLocalDescription()をコールして設定する

#接続を受け入れる側
A-1. RTCPeerConnectionを生成する
A-2. RTCPeerConnection#createAnswer()をコールする
A-3. RTCPeerConnection#setLocalDescription()をコールして設定する
※A-2の操作は先に接続要求してきている、SDPを設定しておく必要があります

○相手のSDPを設定する

#接続を要求する側/#接続を受け入れる側
A/O-1. RTCPeerConnection#setRemoteDescription()をコールする。

[サンプルコード]

○サンプルコード

WebRTCを利用して、テキストを送る事ができます。
※通常は、SDPデータを交換するのに、WebSocketを使います。しかし、今回のサンプルでは、WebSocket用のサーバーを用意する必要はありません。その部分は手動で行うように作りました。


[次回]

....次回は、WebRTCを使って、何かします。たぶん、Torrentの考え方を応用したサンプルを紹介します。