[HTML5] WebSocketでMessagePackを使う

MessagePackとは

MessagePackとは、バイナリシリアライゼーションフォーマットです。
最近はクライアント/サーバ間でデータをやりとりする場合、JSONフォーマットが非常によく使用されていますが、
WebSocketでデータの送受信をする際にもJSON.stringifyを使用してJSON文字列を使っているのではないでしょうか。
MessagePackを使用した場合、JSONにくらべて高速に動作し、データサイズもコンパクトになるという特徴があります。

今回はnode + websocketにおいてMessagePackでデータの送受信をおこなってみましょう。

環境構築方法

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

  • OS : MacOS X 10.9
  • node.js : v0.10.21
  • socket.io: 0.9.16

node.jsについては公式ページ等を参考にしてインストールしておいてください。
今回hサンプルで使用するプログラム用ディレクトリを作成し、npmを使用して必要なライブラリをインストールしておきましょう。

% mkdir msgPack-webSocket
% cd msgPack-webSocket
% npm install ws express msgpack-js

今回は、WebSocketはシンプルなwsを、MessagePackモジュールはmsgpack-jsを使用します。

WebsocketでMessagePackフォーマットデータを送信

サーバ側のプログラムを作成

まずはサーバ側のプログラムを作成します。ここでは、後に作成する画面にアクセスしたらWebSocketの接続を確立し、
固定のオブジェクト情報をMessagePackでsendしています。

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

app.use(express.static(__dirname + '/public'));

var server = http.createServer(app);
server.listen(8080);

//通信で使用するオブジェクト情報
var message = {
    name: "taro",
    company: "classmethod.inc",
    address: {
        country:"japan",
        city: "tokyo",
        street:'xxx'
    },
    pthone:"xxx-xxxx-xxxx",
    email:"taro@taro.com",
    type:true,
    job: "programmer",
    language:["javascript","ruby","java"]
};

var wss = new WebSocketServer({server: server});
wss.on('connection', function (ws) {

  //MessaePack形式にエンコード
    var sendPack = msgpack.encode(message);
    ws.send(sendPack, {binary: true});

    ws.on('close', function () {
        console.log("close");
    });
});

encode関数を使用することで、オブジェクトをMessagePackフォーマットに変換しています。
なお、wsモジュールでバイナリ情報のやりとりをするためには、send時にbinaryオプションをtrueにしなければなりません。

クライアント側プログラムを作成

サーバ側ではmsgpack-jsでエンコードしますが、クライアント側でデコードするためにmsgpack-javascriptを取得します。

% git clone https://github.com/msgpack/msgpack-javascript.git

次に、publicディレクトリを作成し、そこにmsgpack-javascript/msgpack.codec.jsをコピーします。
そして同じ場所にindex.htmlファイルを作成しましょう。

<!DOCTYPE html>
<html>
<head>
    <script src="msgpack.codec.js"></script>
    <script>
        function updateData(message) {
            document.getElementById('name').innerHTML = message.name;
            document.getElementById('company').innerHTML = message.company;
            document.getElementById('city').innerHTML = message.address.city;
            document.getElementById('job').innerHTML = message.job;
        }

        var host = window.document.location.host.replace(/:.*/, '');
        var ws = new WebSocket('ws://' + host + ':8080');
        ws.binaryType = 'arraybuffer';
        ws.onmessage = function (event) {
            updateData(msgpack.unpack(new Uint8Array(event.data)));
        };
    </script>
</head>
<body>
<strong>User Data</strong><br>
name:<div id='name'></div><br>
company:<div id='company'></div><br>
city:<div id='city'></div><br>
job:<div id='job'></div><br>
</body>
</html>

WebSocketでうけとったデータをmsgpack#unpack関数でデコードしています。
nodeサーバを起動してlocalhost:8080にアクセスすると、MesagePack形式でサーバから取得したデータが表示されます。

まとめ

サイズを計測してみるとわかりますが、JSON.stringifyで文字列化したデータより、
MessagePack形式のデータのほうが小さくなっています。
MessagePackについては、色々と問題もありますが、
大量のデータをやりとりする必要があり、少しでもデータ量を少なくしたい場合にはMessagePackを使ってみてはいかがでしょうか。

参考サイトなど