噂のnode.websocket.jsでサーバサイドJSとHTML5 WebSocketを体験してみたの巻
WebSocketを体験してみたいのと、サーバサイドJSを試したいのと、さらにはmac版のChromeをインストールしてみたという条件が重なり、これはもう深夜だけどnode.websocket.jsを試してみるしかないな、という状況に追い込まれました。
構成
最近あたらしく調達したばかりのmacbook air にvirtualboxを入れています。その上でCentOSが動いています。
macbookをクライアントに、CentOS側をサーバとみたてて話を進めていきます。
ちなみに、virtualboxではアダプタ1をNATに、アダプタ2をホストオンリーアダプタ(IPはstaticに設定)としているので、CentOSからは外にも抜けられるしmacbook側からも自由にアクセスできます。ごきげんな環境です。
Node.JSのインストール
まずは土台となるnode.jsが必要。ソースをダウンロードしてくるか、もしくはgitからcloneするかします。
展開して./configure & make します。やや時間かかりますが、とくに問題なくコンパイルできました。
make test すると私の環境では「abが入ってないよ」と文句言われましたが、しょうがないじゃんapache入れてないんだから。なのでシカトしてsudo make install。
/usr/local/bin/nodeがインストールされました。
さて、これでgoogle V8エンジンによるサーバサイドjavascriptな環境ができたはずです。早速ためしてみます。
var sys = require('sys'), http = require('http'); http.createServer(function (req, res) { setTimeout(function () { res.sendHeader(200, {'Content-Type': 'text/plain'}); res.sendBody('Hello World !\n'); res.finish(); }, 2000); }).listen(8000); sys.puts('Server running at http://127.0.0.1:8000/');
http://nodejs.orgに書いてあったサンプルのままですが、これをexample.jsなど、適当な名前で保存します。
そしてnodeでjsを走らせます。
[miki@gamella nodejs]$ node example.js
Server running at http://127.0.0.1:8000
おお、サーバが起動した!netstat で確認してみたらちゃんと8000番でlistenしてるよ!
macbook側(クライアント側)からHTTPをたたいてみます。
godzilla:Hacks miki$ lwp-request http://gamella:8000/
Hello World !
godzilla:Hacks miki$
ちゃんと返ってきました!
次にTCPサーバのサンプルもあるので、それも試してみました。
var tcp = require('tcp'); var server = tcp.createServer( function(socket) { socket.setEncoding("utf8"); socket.addListener("connect", function() { socket.send("hello\r\n"); }); socket.addListener("receive", function(data){ socket.send(data); }); socket.addListener("eof", function(){ socket.send("goodby\r\n"); socket.close(); }); }); server.listen(7000, '192.168.56.101');
これもサンプルのままなんですが、最後の行だけオリジナルとは変えています。
オリジナルでは「server.listen(7000, "localhost")」となっていましたが、
自分のサーバ環境(virtualbox上のCentOS)だとlocalhostと指定するとアダプタ1(NAT)のIPになってしまうので、
ここではアダプタ2(ホストオンリーアダプタ)の方のIPを直で書いています。
(本質とは関係ないことなので、どうでもいいことですが。)
なにはともあれ、こんな簡単にサーバサイドJSが実現できてしまって、ちょっと驚きです。
今までは事あるごとにperlでAnyEvent/POEでサーバを書いてきましたが、ちょっとした用途であればJavascriptでもいけそうです。
node.js.websocketを試してみる
さぁて、ようやく本題です。HTML5 WebSocketです!
まずはここのサイトをザッと読んでおくといいでしょう。
http://devthought.com/blog/2009/12/nodejs-and-the-websocket-protocol/
- Node.JSを読んで触発されてNode.JS.Websocketを書いたよ
- WebSocketいいよ COMETの対抗馬だよ
- Node.JSはネットワークなイベントドリブンなフレームワークでgoogleのV8エンジン搭載だよ
- loggingにはRedis使うけどなくても大丈夫だよ
- WebSocketはまだ限られたブラウザでしか使えないよ(Webkit, Chromium, trunk Firefox (and possibly Opera) have a decent degree of support of WebSocket)
ほかにも最後の方で今後の抱負みたいなことがかいてありますが、まぁだいたいこんな内容のことが書いてあります。
というわけでさっそくソースを落としてきます。
http://github.com/guille/node.websocket.js/
README.mdの最初の方をサラリと読んだだけなんですが、どうやら簡単に使えるみたいです。
まずは同梱されているtest/test.htmlをサーバ側に設置します。
あ、そういえばapache入れてないんだった。面倒いからyum install httpd してしまえ。えいっと。
test.htmlはそのまま使えます。メインのjavascript部分だけ書き出しておきます。
<script> var webSocket = new WebSocket('ws://192.168.56.101:8080/time'); webSocket.onopen = function(event){ document.getElementById('time').innerHTML = 'waiting for socket'; webSocket.send('start'); }; webSocket.onmessage = function(event){ var object = JSON.parse(event.data); document.getElementById('time').innerHTML = object.time; }; webSocket.onclose = function(event){ document.getElementById('time').innerHTML = 'socket closed'; }; </script>
これがWebSocketかぁ。なんだかえらく簡潔なコードですね〜。
いずれ、HTML5が本格普及した暁には、こんな簡単なコードで永続セッション張れてしまうようになるんですね。
(いつ頃になるのかは怪しいところですが・・・)
つづいてサーバ側です。
node runserver.js とたたけば起動するんですが、何度も書いている通り 自分の環境ではホスト名をIPにしないとだめなので、--hostオプションをつけます。
[miki@gamella node.websocket.js]$ node runserver.js --host="'192.168.56.101'"
[Wed Dec 16 2009 03:16:58 GMT+0900 (JST)] [info] 0 clients connected
ふむ。websocketサーバが起動した。0 clients connected だってさ。
ではでは、クライアント側(macbook)からブラウザでアクセスしてみます。ブラウザはmac版のGoogle Chrome 4.0です。
やた!成功!。。。ってなんかえらく地味なデモですね。
でもちゃんと現在の時刻がPushされて画面上で更新されています。
ちなみにコンソール上ではこんなログが出力されました。
[miki@gamella node.websocket.js]$ node runserver.js --host="'192.168.56.101'"
[Wed Dec 16 2009 03:22:16 GMT+0900 (JST)] [info] 0 clients connected
[Wed Dec 16 2009 03:22:21 GMT+0900 (JST)] [info] 0 clients connected
[Wed Dec 16 2009 03:22:26 GMT+0900 (JST)] [info] 0 clients connected
[Wed Dec 16 2009 03:22:31 GMT+0900 (JST)] [info] [client 192.168.56.1] Server created
[Wed Dec 16 2009 03:22:31 GMT+0900 (JST)] [info] [client 192.168.56.1] Performing handshake
[Wed Dec 16 2009 03:22:31 GMT+0900 (JST)] [info] [client 192.168.56.1] Handshake sent
[Wed Dec 16 2009 03:22:31 GMT+0900 (JST)] [info] 1 clients connected
[Wed Dec 16 2009 03:22:36 GMT+0900 (JST)] [info] 1 clients connected
実際のところどうなのか?
見た目はぱっとしませんが、WebSocketにはちょっと面白い一面があります。
wsプロトコルはHTTPをベースとしている、ということです。
自分はFlash-XMLSocketの用に、socket的にハンドリングしているのかと思っていたんですが、どうやら違うようです。
実際にtcpdumpしてみたんですが、HTTPのコネクションが確立した後、jsonでやり取りしている様子を確認しました。
しかしなんでわざわざHTTP的なステージでやり取りさせる必要があるんだろ??
ここまで書いてきて何なんですが、これだけのことならFlash-XMLSocketで既にできているんだよなぁ、とか思ったりして。
リアルタイムWebの本命となるのは、COMETなのかXMLSocketなのか、はたまたWebSocketなのか?
google waveの動きも含めて、どこらへんの技術がデファクトになるのか、今後もしばらく注目する必要がありそうです。