MessagePackを使ってみた
HTML(画面)とサーバサイドでやり取りする形式としては、リクエストなら単純ならパラメータでも良いが、レスポンスにはJSONやXMLを使うことが多い。まあ、HTMLを返すというパターンも場合によってはある。JSONにしろXMLにしろ、データが膨らみがちで、ちょっとぐらいなら良いが、大量データやパフォーマンスを意識しだすと改善したくもなる時がある。Googleが以前Protocol Buffersを出していたが、それとは別のMessagePackを今回使ってみた。
特徴としては効率的なバイナリシリアライゼーションフォーマットであり、JSONの様に様々な言語で、データ交換出来るが、データが小さくて済み、変換も早い。簡単な例だと小さい数値、例えば10ならJSONだと2bytes(2文字)かかってしまうが、バイナリなら1byteで済む。
こういったバイナリデータのやり取りはAjaxなどでは不向きだと思っていて、どちらかと言うと生のソケット通信を行うアプリ(もしくはゲーム)やWebSocketと相性がいいのだろうと思う。だが、使うだけでは面白く無いのでAjax(jQuery)でMessagePackをやり取りするにはどうすればいいのかを試してみようと考えた。
まずは受信から。JavaScript側はmsgpack-javascriptを使い、サーバ側はData::MessagePackを利用した。
$.ajaxSetup({ converters: { 'text msgpack': function(packed) { if(packed != '') return msgpack.unpack(packed); return ''; } } }); $.ajax({ type: "GET", url: "/get_msgpack", dataType: "msgpack", success: function(data) { console.debug(data); } });
いちいちコールバックで変換するのもアレなのでConvertersを利用してmsgpackをunpackするようにしてやるとあまり気にしなくて良い感じになる。サーバサイドとしてContent-typeとしては「application/x-msgpack; charset=x-user-defined」の様にcharsetを指定しないと上手く行かなかった。
データとして以下のJSON的な意味の内容を送ったところ22bytesだった。(以下のJSONは32bytes)
{"hoge":"hoge_value","num":"13"}
次は送信。
msgpack.upload('/send_msgpack', {data: {'k1': 'v1'}}, function(data, option, resp) { console.debug('ok'); });
jQueryでバイナリデータを送信する方法がわからなかったので、結局msgpack.jsのuploadを使った。中身はMessagePackしたデータをBASE64エンコードしてから送信するという仕組み。なのでサーバ側ではBASE64を解除してからunpackする事で対応。
リアルタイムを求められるネットゲームや、大量データを扱う場合には非常に優れたフォーマットであり、ネットワーク越しでは無くファイルとして保存する形式としても使えるだろう。下手にXMLとかで保存するよりよっぽど小さくなると思われる。ただ、やはりバイナリなので転送されているデータを見ても人間には内容がわからない、文字コードの変換も自分でやらないといけない等のデメリットもある。条件や用途によって分けて使い分ければ上手くメリットを享受出来るだろう。