Comet/Ajaxの上を行く技術
上を行くかどうかは知りませんが :-p
Ajaxはクライアントの都合でサーバーに通信を仕掛けるpull型の通信ができ、Cometはサーバーが好きなタイミングでクライアントへデータを送りつけるpush型の通信ができるわけですが、新たに双方向の通信ができる技術を開発しました。
具体的には、JavaScriptとサーバーの間で双方向のRPCができます。すなわち、サーバーからクライアント側のJavaScriptのメソッドが呼べるし、逆にクライアント側からサーバー側のメソッドを呼ぶこともできます。
サーバー側で call("addMessage", "Hello!") とやると、JavaScript側の function addMessage(msg) { ... } という関数が呼ばれたりします。
この技術を使って、試しにチャットシステムを作ってみました > デモ (ソースコード)*1
リアルタイムでチャットができるほか、接続しているユーザーの数もリアルタイムで更新されます。かなり軽快なレスポンスで使えると思います。
(Operaで接続すると発言が表示されないというバグがあります。原因不明><)
仕組みはどうなっているかと言うと、通信部分にFlashを使っています。
Flashとサーバーとの通信には、ActionScriptのSocketを使っています。
FlashとJavaScriptには相互に連携できる機能があるので、それを使っています。外部APIを使用したFlashとJavaScriptの接続 - Adobe - デベロッパーセンター
サーバー側のライブラリは、今のところRubyで書かれています。イベントループにEventMachineを使っているので、そこそこの接続数にも耐えられる、かもしれません。
プロトコルは単純なJSON-RPCなので、他の言語で実装するのも簡単だと思います。
さて、実際のアプリケーションでは、JavaScript側のコードは↓こんな感じになります。
<div id="flashcontent"></div> <!-- ここに0ピクセルのswfがロードされる --> <script type="text/javascript"> // サーバーに接続する var meteor = new Meteor("Meteor.swf", "flashcontent", function(){ // crossdomain.xmlを読み込む meteor.loadPolicyFile("127.0.0.1", 5757); // コールバック関数を指定して接続 meteor.connect("127.0.0.1", 9240, connected, failed, closed); }); // 接続できたら呼ばれる function connected() { // サーバーがaddMessage関数を呼べるようにする meteor.setHandler("addMessage", addMessage); } // 接続に失敗したら呼ばれる function failed(msg) { alert("connect failed: " + msg); } // 接続が切断されたら呼ばれる function closed() { alert("closed"); } /** 発言をHTMLに書き込む * @param msg チャットのメッセージ */ function addMessage(msg) { var li = document.createElement("li"); li.textContent = msg; li.innerText = msg; document.getElementById("comment").appendChild(li); } /** サーバーに発言を送る */ function submitMessage() { // サーバー側のmessage関数を呼ぶ meteor.call("message", [document.getElementById("body").value]); return false; } </script> <!-- 発言フォーム --> <form onsubmit="return submitMessage();"> <input type="text" name="body" id="body" /> <input type="submit" value="submit" /> </form> <ul id="comment"></ul> <!-- ここに発言を追加していく -->
(loadPolicyFileはFlash Player 9,0,115,0の<policy-file-request/>に対処する方法を参照)
接続する → 呼ぶ/呼ばれる という簡単な構図です。サクサクな感じですねー。
実際のDOMの操作にはjQueryなどを使うのがいいと思います。
サーバー側は↓こんな感じです。短い!
require 'meteor' $clients = [] class MeteorChat < Meteor::Handler # 新しいクライアントが接続してくるごとにinitializeされる def initialize(*args) super $clients << self end # クライアントから呼ばれる # 発言を受け取って、すべてのクライアントに転送する def message(msg) del = [] $clients.each {|c| begin # JavaScript側のaddMessage関数を呼ぶ c.send_request("addMessage", msg) rescue # 失敗したら削除 del << c end } del.each {|d| $clients.delete d } end # 接続が切断されたときに呼ばれる def unbind $clients.delete self end end Meteor.start :Handler => MeteorChat, :Port => 9240
Cometと比べた問題として、プロトコルがHTTPではないので、ファイアウォールを越えにくいという問題があります。一方でCometほどブラウザの実装に依存していないので、実装は楽です。
というわけで、Ajax、Cometに次ぐ次世代の技術として期待される(?)わけですが、名前が思いつきません。
仮にMeteorと言う名前が付いているのですが、同じ名前でCometサーバーの実装があり、思いっきりカブっています。
Ajax、Cometと同じように洗剤の名前を付けるとすれば、アタックとかホーミングとかジョイとかも面白いかなー思ったのですが、どうもしっくりこない。
何かいい名前をひらめいたら教えてくださいm(_ _)m
*1:このデモは近いうちに消滅します