RTMFP, Stratusを試してみた
UDPベースのP2P通信のためのプロトコルRTMFPと、それをサポートするサービス「Stratus」。
Adobe Labs - Stratus
通信部分はきれいに隠蔽されていて、ActionScriptから使いやすくなっています。
勉強がてら、文字列のメッセージを1対1で送受信する簡単なプログラムを書いてみました。
<?xml version="1.0"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="creationCompleteHandler(event);"> <mx:Script> <![CDATA[ import flash.events.NetStatusEvent; import flash.net.NetConnection; import flash.net.NetStream; private const URL_CONNECT:String = "[StratusのURL]"; private const PUBLISH_NAME:String = "rtmfp_test"; private const STATE_NOT_CONNECT:int = 0; private const STATE_CONNECT:int = 1; [Bindable] private var state:int = STATE_NOT_CONNECT; private var netConnection:NetConnection = null; private var sendStream:NetStream = null; private var recvStream:NetStream = null; private function creationCompleteHandler(event:Event):void { netConnection = new NetConnection(); netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnectionHandler); netConnection.connect(URL_CONNECT); } private function netConnectionHandler(event:NetStatusEvent):void { logText.text += "NetConnection event: " + event.info.code + "\n"; switch (event.info.code) { case "NetConnection.Connect.Success": logText.text += "my ID: " + netConnection.nearID + "\n"; createSendStream(netConnection.nearID); break; case "NetConnection.Connect.Closed": state = STATE_NOT_CONNECT; break; case "NetConnection.Connect.Failed": state = STATE_NOT_CONNECT; break; case "NetStream.Connect.Success": state = STATE_CONNECT; break; case "NetStream.Connect.Closed": hangUp(); state = STATE_NOT_CONNECT; break; } } private function hangUp():void { if (recvStream) { recvStream.close(); recvStream.removeEventListener(NetStatusEvent.NET_STATUS, recvStreamHandler); recvStream = null; } } private function createSendStream(myID:String):void { sendStream = new NetStream(netConnection, NetStream.DIRECT_CONNECTIONS); sendStream.addEventListener(NetStatusEvent.NET_STATUS, sendStreamHandler); sendStream.publish(PUBLISH_NAME); var c:Object = new Object; c.onPeerConnect = function(caller:NetStream):Boolean { logText.text += "onPeerConnect: " + caller.farID + "\n"; if (!recvStream) { createRecvStream(caller.farID); } return true; } sendStream.client = c; } private function createRecvStream(farID:String):void { recvStream = new NetStream(netConnection, farID); recvStream.addEventListener(NetStatusEvent.NET_STATUS, recvStreamHandler); recvStream.play(PUBLISH_NAME); var o:Object = new Object(); o.onIm = function(msg:String):Boolean { logText.text += msg + "\n"; return true; } recvStream.client = o; } private function sendStreamHandler(event:NetStatusEvent):void { logText.text += "sendStreamHandler event: " + event.info.code + "\n"; } private function recvStreamHandler(event:NetStatusEvent):void { logText.text += "recvStreamHandler event: " + event.info.code + "\n"; } private function callButtonClickHandler(event:Event):void { createRecvStream(targetUserID.text); } private function sendButtonClickHandler(event:Event):void { logText.text += msg.text + "\n"; sendStream.send("onIm", msg.text); msg.text = ""; } ]]> </mx:Script> <mx:ViewStack selectedIndex="{state}" resizeToContent="true"> <mx:HBox> <mx:Label text="Target ID:"/> <mx:TextInput id="targetUserID" width="400" /> <mx:Button id="callButton" label="call" click="callButtonClickHandler(event);" /> </mx:HBox> <mx:HBox> <mx:Label text="Message:"/> <mx:TextInput id="msg" width="400"/> <mx:Button id="sendButton" label="send" click="sendButtonClickHandler(event);" /> </mx:HBox> </mx:ViewStack> <mx:TextInput id="logText" width="500" height="300" /> </mx:Application>
※2/16 AM1:03 切断処理を追加
以下のようにして動作を確認できます。
- ブラウザで2つ開く
- 一方の「my ID」の値を、もう一方の「Target ID」にコピペして「call」をクリック。これでP2P接続ができる
- 一方の「Message」に適当な文字列を入れて「send」をクリックし、文字列メッセージを送信。するともう一方で文字列メッセージを受信する。
パケットロス対策とかパケットの届く順番とかは、どうなっているんだろう。次はそのあたりを調べてみないと。