Node.jsからSocket.IOを使うための事前知識


Node.jsからSocket.IOを使う上で知っておくべきWebSocketの背景やSocket.IOの知識についてまとめてみました。
後半はインストール方法とサンプルになります。

# 1. Socket.IOとは

## 1.1. HTTP
クライアントからサーバーにリクエストを送り, サーバーはそれに対してレスポンスを返すというプロトコルです。
サーバーからクライアントに対してリクエストや通知を送信する方法は用意されていません。

## 1.2. ポーリング
クライアントからサーバーに定期的にリクエストを送信する方法。
無駄なリクエストが増えてしまうという欠点があります。

## 1.3. WebSocket
2011年にRFC6455で仕様が提案されたサーバーとクライアントの双方向通信用のプロトコルで, 非同期かつ双方向の通信を可能にしています。
ブラウザのバージョンによってはサポートしていないものもあるので注意が必要です。
>[RFC6455 The WebSocket Protocol](http://tools.ietf.org/html/rfc6455)

## 1.4. Socket.IO
WebSocketなどの非同期双方向通信をNode.jsから利用できるようにしたモジュールです。
環境に合わせてWebSocketやFlashPlayerのSocketAPI, ロングポーリングなど使用する技術を自動的に判断してくれるので, 開発者は接続プロトコルを意識することなく非同期双方向通信を実現できます。
> [公式サイト socket.io](http://socket.io/)

# 2. Socket.IOのインストール
## 2.1. インストール
```
npm install socket.io
```

## 2.2. 実行環境
* OS: CentOS 6.4
* Node.js: 0.10.3
* npm: 2.7.0
* socket.io: 1.3.5

# 3. サンプル

## 3.1. 8000番ポートでHTTPとSocket.IOサーバーの待ち受け

```javascript:server.js
var fs = require('fs');
var http = require('http');
var server = http.createServer();

server.on('request', function(req, res) {
  var stream = fs.createReadStream('index.html');
  res.writeHead(200, {'Content-Type': 'text/html'});
  stream.pipe(res);
});
var io = require('socket.io').listen(server);
server.listen(8000);
```

サーバー側ではsocket.ioモジュールを読み込み, listen関数を実行することによって待ち受けを行います。
引数ではhttp.Serverクラスのインスタンスを指定していますが, 直接ポート番号を指定することも可能で, Socket専用サーバーの場合に使われます。
ブラウザで8000番にアクセスしてみるとindex.htmlの内容が表示されるはずです。
> 小ネタですがstreamを使ってindex.htmlを読み込むことで, fs.readFileを使うよりもネストが浅くなり, メモリを食わなくなります。

## 3.2. コネクション時にイベントを送信する【サーバー側】
```javascript:server.js
// 上記のserver.jsに以下の内容を追加

io.sockets.on('connection', function(socket) {
  socket.emit('greeting', {message: 'hello'}, function (data) {
    console.log('result: ' + data);
  });
});
```

サーバー側ではクライアント側の接続を受け付けると, io.socketsオブジェクトにconnectionイベントが発生します。
このとき引数としてsocketオブジェクトが発生するので, socket.emitメソッドを使用してイベントをクライアントに送信します。
引数は順にイベント名, 送信するデータオブジェクト, コールバック関数となっていて, コールバック関数ではクライアントからデータを受け取って使用することができます。
今回のプログラムではクライアントから送信されたデータをconsole.logで表示させています。

## 3.3. コネクション時にイベントを送信する【クライアント側】

```HTML:index.html
<html>
  <head>
    <title>Socket.IO Test</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      $(function() {
        var socket = io.connect();

        socket.on('greeting', function(data, fn) {
          var answer = confirm(data.message);
          fn(answer);
        });
      });
    </script>
  </head>
  <body>
    <h1>Socket.IO Test</h1>
  </body>
</html>
```

クライアント側ではjQueryとSocket.IOのクライアント用ライブラリを読み込んでいます。

```js
var socket = io.connect();
```

上記の一行ではサーバー側とのコネクションを作成しています。
io.connectメソッドはURLを引数に取ることができ, Socket.IOサーバーのURLを指定することができます。
デフォルトではHTTPサーバーと同じURLを指定します。

```js
socket.on('greeting', function(data, fn) {
  var answer = confirm(data.message);
  fn(answer);
});
```

この部分ではサーバー側からsocket.emitメソッドでイベントが送られてきた際の処理を関数として登録しています。
confirmメソッドで送られてきたデータを表示し, socket.emitメソッドで指定したコールバック関数にconfirmメソッドの結果を渡しています。


# 4. 終わりに
以上で本稿は終了です。
サンプルプログラムはGithub上に公開していますので, 不明な点などあれば参考にしてください。
> https://github.com/junishitsuka/qiita/tree/master/socket

これからはNode.jsとSocket.IOを使ったリアルタイム通信ゲームを作ってみたいと思うので, そちらも投稿できたらと思います。
Enjoy Socket.IO！