ラベル websocket の投稿を表示しています。 すべての投稿を表示
ラベル websocket の投稿を表示しています。 すべての投稿を表示

2011年10月5日水曜日

WebSocketってなんじゃ?(Node編2 Socket.IOでプッシュ通信)

前回Node編1で、スタンドアローンのHTTPサーバーをつくり、HTTP通信を行いました。

今回は、WebSocketを使用した通信を行ってみます。 WebSocketとは、ブラウザとサーバーの双方向通信のプロトコル規格で、現在標準化団体が仕様を策定中の技術です。chromeやsafariなど、いくつかのモダンブラウザがサポートしており、これが一般的に使用されると、いままでのサーバーアプリケーションの作り方が大きく変わってくる可能性がある、注目の技術です。

ここで使用するのは、Socket.IO というnode.jsのモジュールです。 node.jsはモジュールという単位でライブラリを管理しており、npmというモジュール管理ツールで簡単にいろいろなモジュールを追加削除できます。これはrubyでいうgemのようなものです。
Socket.IOはただnode.jsでWebSocketを実装しているだけではなく、モダンブラウザ以外のWebSocketを使用できないブラウザでも、AjaxやFlashなど他の代替手段があるかどうかを自動的に検知して通信方式を自動で選択されるので、ブラウザの対応をあまり気にしなくてもよくなっています。
また、Socket.IOは WebSocketとその代替手段において、クロスドメイン通信を可能にしています。

早速実践してみます。 まず最初にnpmをインストールします。
$ curl http://npmjs.org/install.sh | sh
$ npm install -g socket.io


socket.ioのインストールでエラーが出る場合がありますが、その場合はtarが古いので、tarを最新にしておきます。
$ cd /usr/local/src
$ wget http://ftp.gnu.org/gnu/tar/tar-1.26.tar.gz
$ tar xzvf tar-1.26.tar.gz
$ cd tar-1.26
$ ./configure
$ make
# make install


socket.ioをインストールします。
$ curl http://npmjs.org/install.sh | sh
$ npm install -g socket.io

※エラーになる場合は curl -L http://npmjs.org/install.sh | sh とやると良いようです。

これで実装の準備が整いました。
それでは実装を始めます。
今回は、メッセージを送信したら見ている全員にメッセージを表示させる、簡単なチャットの仕組みを作ってみます。

サーバー側

/opt/memorycraft/node/socketsample.js
require.paths.push('/usr/local/lib/node_modules');

var server = require('http').createServer(function(req, res){
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('server connected');
});
server.listen(1337);

var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {
  socket.emit('info', { msg: 'welcome' });
  socket.on('msg', function (msg) {
    io.sockets.emit('msg', {msg: msg});
  });
  socket.on('disconnect', function(){
    socket.emit('info', {msg: 'bye'});
  });
});


サーバー側では任意のポート(ここでは1337)を開放したhttpサーバーにsocket.ioをつなげてリスン状態にします。
通信の確立(connection)や切断(disconnect)などのビルトインイベントや、自分のアプリケーションで使用したいオリジナルのイベント(ここではmsg)のイベントハンドラを定義します。
このコードでは接続したときに"welcome"、切断したときに"bye"をそのユーザーに、あるユーザーから"msg"というイベントが送られたら全員に"msg"というイベントを、それぞれプッシュ送信しています。

クライアント側

/var/html/www/test/node/index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
  <script src="http://xxx.xxx.xxx.xxx:1337/socket.io/socket.io.js"></script>
  <script type="text/javascript">
  $(function(){
    var socket = io.connect('http://xxx.xxx.xxx.xxx:1337/');
    socket.on('connect', function() {
      $("#log").html($("#log").html() + "<br />" + 'connected');
      socket.on('info', function (data) {
        $("#log").html($("#log").html() + "<br />" + data.msg);
      });
      socket.on('msg', function(data){
        $("#log").html($("#log").html() + "<br />" + "<b>" + data.msg + "</b>");
      });
      $("#send").click(function(){
        var msg = $("#msg").val();
        if(!msg){
          alert("input your message");
          return;
        }
        socket.emit('msg', msg);
      });
    });
  });
  </script>
  <title>nodetest</title>
</head>
<body>
  <input id="msg" type="text" style="width:400px;"></input>
  <input id="send" type="button" value="send" /></br >
  <div id="log" style="width:400px;height:400px;overflow:auto;border:1px solid #000000;"></div>
</html>

クライアント側からはサーバー側の1337ポートに接続しますが、サーバー側は実際にファイルを自分で配置しなくてもSocket.IOが勝手にクライアント側のライブラリを/socket.io/socket.io.jsとして配信してくれます。
そのファイルをscriptファイルでロードするようにし、あとは接続部分とサーバーからのイベントのハンドラを定義します。また、ボタンを押したらテキストをサーバー側に送信するように記述します。


それでは、サーバー側のコードを実行してみます。
$ node /opt/memorycraft/node/socketsample.js
   info  - socket.io started

ブラウザでhtmlを表示します。

サーバー側からの"welcome"メッセージが表示されていることがわかります。
また、メッセージを入力して送信すると、

メッセージ欄にサーバーから送られてきているのがわかります。

別のブラウザでも開いておき、そちらからメッセージを送信するともう一方のブラウザにメッセージが表示されることが分かります。


このように、socket.ioを利用することで多くのブラウザで簡単にWebSocketを実現することができます。
WebSocketは通信内容が少なく、コネクションやリソースの消費が少ないので、ゲームやソーシャルサイトなどのマルチユーザーアプリや、クライアントのログ集計など、様々な分野での利用が期待できます。
今日はここまで。

2011年9月28日水曜日

WebSocketってなんじゃ?(Node編1 node.jsのインストール)

かなりいまさらですが、nodeについて。
Node.jsは、非同期イベント駆動モデルのサーバーサイドJavaScript環境で、非ブロッキングI/O(入出力が完了しないうちに他の処理を開始できる)という方式でクライアントからの多数のリクエストを短い時間で処理することができます。

Node.jsではWebSocketを利用することで双方向のメッセージ送信を可能にします。
サーバーからクライアントに情報を渡す仕組みとしては、Ajaxがポーリングにより毎回コネクションを生成したり、Cometのロングポーリングによる擬似プッシュを実現しているのに対して、WebSocketは一度コネクションが生成されたらそのコネクション上で何度でも双方向にメッセージの送受信を行えるため、サーバーのリソースもクライアントの待機時間も節約できます。


それでは、さっそくnodeをインストールしてみます。
$ mkdir -p ~/src/git
$ cd ~/src/git/
$ git clone --depth 1 git://github.com/joyent/node.git
$ cd node
$ git checkout v0.4.11
$ ./configure
$ make
# make install


インストールができたら、以下のようなサンプルを作ってみます。
$ vi hello.js
~
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337);
console.log('Server is running');
~


実行します。
$ node hello.js
Server is running
※AWS上で構築している場合はSecurityGroupでTCPの1337を開放する必要があります。


ここで、クライアント(Mac)のコンソールで以下のようにアクセスしてみます。
$ curl http://xx.xx.xx.xx:1337/
Hello World


次に、さきほどのhello.jsを以下のように書き換えて実行してみます。
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.write("Hello\n");
  setTimeout(function(){
    res.end('This is the Node World !!!!\n');
  }, 10000);
}).listen(1337);
console.log('Server running');

同じようにアクセスしてみます。
$ curl http://xx.xx.xx.xx:1337/
Hello

すると、一旦ここまでレスポンスが表示され、
10秒後に
$ curl http://xx.xx.xx.xx:1337/
Hello
This is the Node World !!!!
と "This is the node World !!!!" が追加で表示されます。

この時サーバークライアント間では、2つめのワードが返る間もコネクションが維持され、しかもサーバーはその間スループやロックやビジーになることなく他のアクセスの処理などを行うことができます。

見た目にはたったこれだけの違いなのですが、これによりとても多くの可能性をもつことになり様々な応用が期待できます。
今日はここまでです。