WebSocket 事始め by Node.js + Socket.IO


ここまでは情報がかなりたくさんあるので、サクサク行けそう。

####Socket.IO
[リアルタイムWebを構築しやすくする「Socket.IO」とは ](http://codezine.jp/article/detail/7075)によると、「リアルタイムWeb技術の実装方式を隠蔽し、すべてのブラウザ・モバイルデバイスでリアルタイム通信を可能とすること」を目指して開発されている、node.js用サーバ側ライブラリとブラウザ用JavaScriptライブラリのセット、だそうです。
双方向通信で非同期にデータをやり取りする方法は色々あるが、それらをラップして統一したインターフェイスにする事で、保守性や習得しやすさを獲得している、って事でしょうか。独自解釈です。

##環境
ゲスト: CentOS 6.2
ゲスト2: Windows 7 Home Premium SP1 64bit
ホスト: MacBookAir MacOS 10.8
VM: Parallels Desktop 9 for mac
ゲストを対象とし、IPアドレスは 10.211.55.2 とする。
#### ソフトウェア
Nginx: v1.4.3
Node.js: v0.10.20
node-express: v3.4.4
node-forever: v0.10.9
#### サンプルアプリ
[前回](http://qiita.com/ogwmtnr/items/03996d3798facbc600da)のものを流用。
一応作ったときの軌跡を以下に。

```bash:
$ cd
$ express -e SampleApp
$ cd SampleApp
$ npm install
```

##Socket.io インストール
npm でインストールします。

```bash:~/SampleApp
$ npm install socket.io
```

##サンプルアプリを Socket.io 対応
[【初心者向け】node.js(0.10x) + socket.io(0.9x)のサンプルプログラム](http://d.hatena.ne.jp/replication/20130609/1370708498)のサンプルプログラムを流用させていただきました。
クライアント側の`io.connect`で示すURLが、自分の環境では異なったため、そこだけ変更しました。
Nginx からプロキシできるなら、これで良いはず...

```js:~/SampleApp/app.js
/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

app.get('/', routes.index);
app.get('/users', user.list);

server = http.createServer(app); // add
//http.createServer(app).listen(app.get('port'), function(){ // del
server.listen(app.get('port'), function(){ //add
  console.log("Express server listening on port " + app.get('port'));
});

// add start
var socketIO = require('socket.io');
// クライアントの接続を待つ(IPアドレスとポート番号を結びつけます)
var io = socketIO.listen(server);

// クライアントが接続してきたときの処理
io.sockets.on('connection', function(socket) {
  console.log("connection");
  // メッセージを受けたときの処理
  socket.on('message', function(data) {
    // つながっているクライアント全員に送信
    console.log("message");
    io.sockets.emit('message', { value: data.value });
  });
  
  // クライアントが切断したときの処理
  socket.on('disconnect', function(){
    console.log("disconnect");
  });
});
// add end
```

```html:~/SampleApp/views/index.ejs
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
// var socket = io.connect('http://localhost:3000');
var socket = io.connect('http://10.211.55.2/');
socket.on('connect', function(msg) {
  console.log("connet");
  document.getElementById("connectId").innerHTML = 
    "あなたの接続ID::" + socket.socket.transport.sessid;
  document.getElementById("type").innerHTML = 
    "接続方式::" + socket.socket.transport.name;
});

// メッセージを受けたとき
socket.on('message', function(msg) {
  // メッセージを画面に表示する
  document.getElementById("receiveMsg").innerHTML = msg.value;
});

// メッセージを送る
function SendMsg() {
  var msg = document.getElementById("message").value;
  // メッセージを発射する
  socket.emit('message', { value: msg });
}
// 切断する
function DisConnect() {
  var msg = socket.socket.transport.sessid + "は切断しました。";
  // メッセージを発射する
  socket.emit('message', { value: msg });
  // socketを切断する
  socket.disconnect();
}
</script>

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>

  <h1>socket.ioのサンプルプログラム</h1>
  <div id="connectId"></div>
  <div id="type"></div>
  <br>
  <input type="text" id="message" value="">
  <input type="button" value="メッセージを送る" onclick="SendMsg()">
  <input type="button" value="切断する" onclick="DisConnect()">
  <div id="receiveMsg"></div>

  </body>
</html>
```

##Nginx 設定ファイルを WebSocket 対応
プロキシ設定を探している時に、[Nginxの最新安定版がWebSocketのリバースプロキシに対応したそうなので試してみた](http://kitak.hatenablog.jp/entry/2013/04/27/180255)の貴重な情報を得たので、以下の設定を書き加えておく。

```bash:/etc/nginx/conf.d/node-app.conf
server {
	〜略〜
	# for WebSocket
	proxy_http_version 1.1;	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "upgrade";
	〜略〜
}
```

```bash:
$ sudo service nginx reload
```

##node で起動してコンソールを追いながら確認
forever でアプリを動かしている場合は、

```bash:~/SampleApp
$ forever stop app.js
```

で一度動作を止めて、

```bash:~/SampleApp
$ node app
```

で直接起動した方が、コンソール出力を目で追いながら動作を確認できるので、テスト中はこっちの方が良いのかもしれない。
`Command + c`で停止できます。

##node で起動したら最初に Warn 出たんだけど…
[最新Express.jsでのWarning解消](http://qiita.com/ksato9700/items/f7ea00d05b64ec031891)を参考に、`app.js`を一部修正しました。

```js:~/SampleApp/app.js
//〜略〜
  app.use(express.bodyParser());
//〜略〜
//↓
//〜略〜
  // app.use(express.bodyParser());
  app.use(express.json());  app.use(express.urlencoded());
//〜略〜
```

改めて...

```bash:~/SampleApp
$ node app
```

##ブラウザで確認
ホスト、ゲスト2それぞれのブラウザで、
http://10.211.55.2/
にアクセスして、確認。

##あなたの接続ID表示確認、メッセージ送受信と表示を確認
コングラッチュレーション…！

##感謝
参考にさせていただいたサイト管理人の皆様、誠にありがとうございました。