Node.jsでWebSocketを試してみる
Nodejs
- サーバサイドJavascript。
- V8 Javascriptを利用。
- シングルスレッドの非同期処理環境。
- 処理を待たずにcallbackを実行するイベントループ、ノンブロッキングI/Oを実装。
- nodejsの設定は簡単。パッケージ化されているし、buildしてもそれほど時間がかからない。
設定
macでinstallしてみる。以下のどちらか一方を行えば設定は可能だがportのversionは0.2.0、buildの最新は0.4.8。post installは少し時間がかかる。
port install
$ sudo port install nodejs $ node -v v0.2.0make install
$ fetch http://nodejs.org/dist/node-v0.4.8.tar.gz $ tar -xzf node-v0.4.8.tar.gz $ cd node-v0.4.8 $ ./configure $ sudo make install $ ./node -v v0.4.8
実行
日本語ドキュメントにあるサンプルをそのまま実行してみる。サンプルはHttp,Socketサーバ。以下のそれぞれのJavascriptっぽいコードをsample.jsなどのファイルとして保存してnodeコマンドにより実行する。
Http
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, "127.0.0.1"); console.log('Server running at http://127.0.0.1:1337/');起動
$ node http.jsアクセス
ブラウザでhttp://127.0.0.1:1337/にアクセスしてみると Hello Worldが表示される。
Socket
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); }); server.listen(1337, "127.0.0.1");起動
$ node socket.jsアクセス
telnetコマンドによりlistenしているポートにアクセスし、文字列を打つとechoされる。$ telnet 127.0.0.1 1337 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Echo server NodeJS Test NodeJS Test
npm
- npmとはNode.js用のパッケージマネージャ。Pythonのeasy_installみたいなもの。
- npmコマンドによりnode.jsのパッケージをinstallできる。
npmのinstall
まずはnpmコマンドのinstall。
$ fetch http://npmjs.org/install.sh $ chmod +x ./install.sh $ sudo ./install.sh $ npm -v 1.0.6パッケージのinstall
npmコマンドによりWebSocket実装可能なパッケージ(Socket.io)をinstallする。
$ sudo npm install socket.io
WebSocket
nodejsをつかってWebSocketを試してみる。
WebSocketとは
Socket.ioのサンプルを見てみる
npmによりinstallしたsocket.ioパッケージのsampleはnode_modules/socket.io/example/に配置される。node_modules/socket.io/example/server.jsというサーバのサンプルプログラムを見てみる。初心者で全くnodejsに詳しくないが、だいたい以下のような感じだと思う。
- http.createServerでサーバオブジェクト作成。
- server.listen(8080)でポートを指定して起動。
- client.sendでclientにメッセージを送信。
- client.broadcastで全てのclientにメッセージを送信。
/** * Important note: this application is not suitable for benchmarks! */ // 必要なモジュールのrequire var http = require('http') , url = require('url') , fs = require('fs') , io = require('../') , sys = require(process.binding('natives').util ? 'util' : 'sys') , server; //serverのcreate server = http.createServer(function(req, res){ // your normal server code var path = url.parse(req.url).pathname; switch (path){ case '/': res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<h1>Welcome. Try the <a href="/chat.html">chat</a> example.</h1>'); res.end(); break; case '/json.js': case '/chat.html': fs.readFile(__dirname + path, function(err, data){ if (err) return send404(res); res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'}) res.write(data, 'utf8'); res.end(); }); break; default: send404(res); } }), //caseに当てはまらなかった時の404処理 send404 = function(res){ res.writeHead(404); res.write('404'); res.end(); }; //8080ポートで起動 server.listen(8080); // socket.io, I choose you // simplest chat application evar var io = io.listen(server) , buffer = []; //clientとconnectionが張られているとき io.on('connection', function(client){ //clientにbufferを送信 client.send({ buffer: buffer }); //全てのclientにclientidとつながっていることをアナウンス client.broadcast({ announcement: client.sessionId + ' connected' }); //clientからメッセ時を受け取ったとき client.on('message', function(message){ //メッセージ情報をbufferに格納。 var msg = { message: [client.sessionId, message] }; buffer.push(msg); if (buffer.length > 15) buffer.shift(); //メッセージをその他clientにブロードキャストする client.broadcast(msg); }); //clientとの接続が切れたとき client.on('disconnect', function(){ //clientが切断されたことをその他clientにブロードキャストする。 client.broadcast({ announcement: client.sessionId + ' disconnected' }); }); });クライアントhtml
json.jsとsocket.io/socket.io.jsを読み込む必要がある。以下はおれおれ解説。
- new io.SocketでSocketオブジェクト作成。
- socket.connectでサーバとのconnectionを確立。
- socket.on('connect',(省略)でサーバとconnectionが確立されたらハンドリングする。
- socket.on('message',(省略)でサーバからメッセージを受信した時にハンドリングする。
- socket.onのその他 disconnect(切断)、reconnect(再接続後)、reconnecting(再接続中)の時のハンドリング。
<!doctype html> <html> <head> <title>socket.io client test</title> <script src="/json.js"></script> <!-- for ie --> <script src="/socket.io/socket.io.js"></script> </head> <body> <script> //メッセージ出力関数。 function message(obj){ var el = document.createElement('p'); if ('announcement' in obj) el.innerHTML = '<em>' + esc(obj.announcement) + '</em>'; else if ('message' in obj) el.innerHTML = '<b>' + esc(obj.message[0]) + ':</b> ' + esc(obj.message[1]); if( obj.message && window.console && console.log ) console.log(obj.message[0], obj.message[1]); document.getElementById('chat').appendChild(el); document.getElementById('chat').scrollTop = 1000000; } //メッセージ送信 function send(){ var val = document.getElementById('text').value; socket.send(val); message({ message: ['you', val] }); document.getElementById('text').value = ''; } //HTML escape function esc(msg){ return msg.replace(/</g, '<').replace(/>/g, '>'); }; // socketオブジェクト作成 var socket = new io.Socket(null, {port: 8080, rememberTransport: false}); // サーバとのconnection確立 socket.connect(); //メッセージ受信ハンドリング socket.on('message', function(obj){ if ('buffer' in obj){ document.getElementById('form').style.display='block'; document.getElementById('chat').innerHTML = ''; for (var i in obj.buffer) message(obj.buffer[i]); } else message(obj); }); //connection確立ハンドリング socket.on('connect', function(){ message({ message: ['System', 'Connected']})}); //connection切断ハンドリング socket.on('disconnect', function(){ message({ message: ['System', 'Disconnected']})}); //connection再確立ハンドリング socket.on('reconnect', function(){ message({ message: ['System', 'Reconnected to server']})}); //connection再接続中ハンドリング socket.on('reconnecting', function( nextRetry ){ message({ message: ['System', 'Attempting to re-connect to the server, next attempt in ' + nextRetry + 'ms']})}); socket.on('reconnect_failed', function(){ message({ message: ['System', 'Reconnected to server FAILED.']})}); </script> <h1>Sample chat client</h1> <div id="chat"><p>Connecting...</p></div> <form id="form" onSubmit="send(); return false"> <input type="text" autocomplete="off" id="text"><input type="submit" value="Send"> </form> <style> #chat { height: 300px; overflow: auto; width: 800px; border: 1px solid #eee; font: 13px Helvetica, Arial; } #chat p { padding: 8px; margin: 0; } #chat p:nth-child(odd) { background: #F6F6F6; } #form { width: 782px; background: #333; padding: 5px 10px; display: none; } #form input[type=text] { width: 700px; padding: 5px; background: #fff; border: 1px solid #fff; } #form input[type=submit] { cursor: pointer; background: #999; border: none; padding: 6px 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; margin-left: 5px; text-shadow: 0 1px 0 #fff; } #form input[type=submit]:hover { background: #A2A2A2; } #form input[type=submit]:active { position: relative; top: 2px; } </style> </body> </html>サンプルのSocketサーバの起動
$ node node_modules/socket.io/example/server.jsアクセス
複数のWebブラウザでアクセスしてコメントを投稿してみるとWebSocketのチャットが利用可能。
http://127.0.0.1:8080/chat.html
リファレンス
- 日本語ドキュメント
http://nodejs.jp/nodejs.org_ja/
- API日本語マニュアル
http://nodejs.jp/nodejs.org_ja/api/index.html
- Node.jsでサーバサイドJavaScript開発入門
http://www.atmarkit.co.jp/fwcr/index/index_nodejs.html
- npm registry