node.jsのいろいろなモジュール23 – wsでWebSocket接続

2013.03.06

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

wsモジュール

wsモジュールは、WebSocketプロトコル(RFC-6455に準拠する)の実装ライブラリです。
socket.ioのように多機能ではありませんが、シンプルな作りで非常に高速に動作するのが特徴です。
※socket.ioも内部でwsを使用しています

環境構築方法

今回使用した動作環境は以下のとおりです。

  • OS : MacOS X 10.7.4
  • Node.js : v0.8.15
  • npm : 1.1.66

適当なディレクトリを作成し、そこでnpmを使用して必要モジュールをインストールします。
今回はexpressも使用するので、いっしょにインストールしましょう。

% mkdir ws
% cd ws
% npm install ws express

wsモジュールを使ったチャット

ありふれた例ですが、wsモジュールとexpressモジュールを使用してシンプルなチャットをつくってみましょう。
まずはサーバ側のモジュールをapp.jsという名前で作成します。

//app.js
var WebSocketServer = require('ws').Server
    , http = require('http')
    , express = require('express')
    , app = express();

app.use(express.static(__dirname + '/'));
var server = http.createServer(app);
var wss = new WebSocketServer({server:server});

expressモジュールからHttpサーバを作成し、wsモジュールのServerの引数にしてWebSocket用サーバオブジェクトを作成します。

WebSocketの接続を保存しておく変数、connectionsを用意しておきます。
WebSocketServerのonメソッドを使用し、接続時、切断時、メッセージ受信時の処理を記述します。

var connections = [];

wss.on('connection', function (ws) {
    connections.push(ws);
    ws.on('close', function () {
        connections = connections.filter(function (conn, i) {
            return (conn === ws) ? false : true;
        });
    });
    ws.on('message', function (message) {
        console.log('message:', message);
        broadcast(JSON.stringify(message));
    });
});

なお、接続時にはconnections変数へ接続オブジェクトを保存し、切断時にはconnections変数から削除します。
broadcastはこの後定義する関数です。

wsモジュールには、Websocketで接続しているユーザー全員にブロードキャストする機能はありません。
接続時に保存している配列を精査して全員にsendメソッドでメッセージを送ります。

function broadcast(message) {
    connections.forEach(function (con, i) {
        con.send(message);
    });
};

server.listen(3000);

最後に3000番ポートでサーバを起動しています。

app.js全文です。

//app.js
var WebSocketServer = require('ws').Server
    , http = require('http')
    , express = require('express')
    , app = express();

app.use(express.static(__dirname + '/'));
var server = http.createServer(app);
var wss = new WebSocketServer({server:server});

//Websocket接続を保存しておく
var connections = [];

//接続時
wss.on('connection', function (ws) {
    //配列にWebSocket接続を保存
    connections.push(ws);
    //切断時
    ws.on('close', function () {
        connections = connections.filter(function (conn, i) {
            return (conn === ws) ? false : true;
        });
    });
    //メッセージ送信時
    ws.on('message', function (message) {
        console.log('message:', message);
        broadcast(JSON.stringify(message));
    });
});

//ブロードキャストを行う
function broadcast(message) {
    connections.forEach(function (con, i) {
        con.send(message);
    });
};

server.listen(3000);

次はindex.htmlファイルです。
sendボタンを押すと、テキストフィールドの文字をブロードキャストします。

<!DOCTYPE html>
<html>
<head>
    <script>
        function send() {
            ws.send(document.getElementById('msg').value);
        }

        var host = window.document.location.host.replace(/:.*/, '');
        var ws = new WebSocket('ws://' + host + ':3000');
        ws.onmessage = function (event) {
            document.getElementById("messages").innerHTML += "<div>" + JSON.parse(event.data) + "</div>";
            console.log(JSON.parse(event.data));
        };
    </script>
</head>
<body>
<strong>ws chat</strong><br>
<input type="text" id="msg"/>
<input type="button" value="send" onclick="send()"/>
<br>
<hr>
<div id="messages"/>
</body>
</html>

サーバを起動し、ブラウザでhttp://localhost:3000/index.htmlを複数ブラウザで開いた後、文字を送信してみてください。
チャットができてますね。

% node app.js

まとめ

node.jsでWebSocketを使いたい場合、ほとんどのケースでsocket.ioを使用しているのではないでしょうか。
しかし、socket.ioほどの機能は必要なかったり(ブロードキャスト機能もありませんが・・・)、
wsをベースにしてライブラリを作成する場合には直接使用することもあるかもしれません。

参考サイトなど