Node.js + WebSocket で双方向通信をはじめる

Node.js のインストール

Mac でやったけど、おそらくLinux 系でも同様にいけるはず。

cd /usr/local/src/
git clone git://github.com/ry/node.git
cd node
./configure
make
sudo make install

Node パッケージ管理 npm のインストール

curl http://npmjs.org/install.sh | sh

Node で Hello World!

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World!\n');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');

hello.js など適当に保存して実行

node hello.js

ブラウザなどで http://127.0.0.1:8124/ へアクセスして “Hello World!” が表示されたらOK.

WebSocket のインストール

WebSocket 用の Node ライブラリ Socket.IO をインストールする

npm install socket.io

本家のサンプルをとりあえず動かしてみる

Server 側のアプリケーションを作成

app.js として、以下のコードをコピペ保存する

var app = require('http').createServer(handler)
  , io = require('socket.io').listen(app)
  , fs = require('fs')

app.listen(8124);

function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

Client 側のView を作成

index.html として、以下のコードをコピペ保存する

<!DOCTYPE html>
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8"/>
    <title>Hello WebSocket</title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>
</body>
</html>

Node.js で WebSocket を動かしてみる

まずは、Node アプリケーションを実行&起動

node app.js

ブラウザで http://127.0.0.1:8124/ へアクセスする。画面が真っ白ならOK. Node を起動したコンソール上にログっぽいメッセージが流れるはず。

Node のデフォルト出力 “Hello Node.js” とテキスト (HTML でなく単なる plain/text) が表示されたら NG.

WebSocket についての補足

従来の Commet などの双方向通信とは異なり、TCP のハンドシェイク手続きを何度も行う必要がなく、サーバとクライアントが一度 TCP コネクションを確立したあとは、そのコネクション上で専用プロトコルを使い必要な通信をすべて行うことが出来る。

具体的には、HTTP 通信でセッションを確立し、その後 WebSocket 通信へ移行する。Firefox の Live HTTP Headers で通信を覗いてみると概要が分かる。

初回はただの HTTP リクエストを送る。

GET / HTTP/1.1
Host: 127.0.0.1:8124
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:14.0) Gecko/20100101 Firefox/14.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive

HTTP 通信から WebSocket 通信への切り替えリクエストを送る。

GET /socket.io/1/websocket/X-8776MBmRib_qXjzMFO HTTP/1.1
Host: 127.0.0.1:8124
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:14.0) Gecko/20100101 Firefox/14.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive, Upgrade
Sec-WebSocket-Version: 13
Origin: http://127.0.0.1:8124
Sec-WebSocket-Key: bmxxAd1YiaYzLLnDb9pAEg==
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

Upgrade: websocket なるヘッダー情報が入っている。その他、WebSocket のハンドシェイクを開始するために、 Sec-WebSocket-Key などが必要となる。

接続確立すると 101 Switching Protocols のレスポンスが返ってくる。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: sk85MqSFg1CGhAYRlSvctpzSALA=

レスポンスヘッダーの中には、Sec-WebSocket-Accept なるセッション確立したことを示すデータが含まれる。

細かい仕様は、RFC6455 The WebSocket Protocol で。