Node.js
nginx
Socket.io

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

More than 3 years have passed since last update.

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

Socket.IO

リアルタイムWebを構築しやすくする「Socket.IO」とは によると、「リアルタイム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

サンプルアプリ

前回のものを流用。
一応作ったときの軌跡を以下に。

$ cd
$ express -e SampleApp
$ cd SampleApp
$ npm install

Socket.io インストール

npm でインストールします。

~/SampleApp
$ npm install socket.io

サンプルアプリを Socket.io 対応

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

~/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
~/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のリバースプロキシに対応したそうなので試してみたの貴重な情報を得たので、以下の設定を書き加えておく。

/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";
    〜略〜
}
$ sudo service nginx reload

node で起動してコンソールを追いながら確認

forever でアプリを動かしている場合は、

~/SampleApp
$ forever stop app.js

で一度動作を止めて、

~/SampleApp
$ node app

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

node で起動したら最初に Warn 出たんだけど…

最新Express.jsでのWarning解消を参考に、app.jsを一部修正しました。

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

改めて...

~/SampleApp
$ node app

ブラウザで確認

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

あなたの接続ID表示確認、メッセージ送受信と表示を確認

コングラッチュレーション…!

感謝

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