MessagePack for C/C++/Ruby アップデート
MessagePackのC,C++,Ruby版をバージョンアップしました。C/C++版は0.4.2、Ruby版は0.3.3です。
主に strict-aliasing rule (goo)に関する問題を修正しました。互換性はAPI・ABI両方で維持されています。
Unpacker#each
Ruby版では、実験的に each(とfeedとfill)メソッドをデシリアライザに実装してみました*1。
ストリーム(ソケットやファイルなど)から、シリアライズされたデータを次々に受信しながら、オブジェクトを1つずつ取り出してくれます。
イベント駆動型のサーバを実装したいときや、MessagePackでシリアライズしたデータが詰め込まれたファイルからオブジェクトを読み出したいときに便利です。高速でもあります。
require 'rubygems' require 'msgpack' # パイプの場合(標準入出力でも可) rpipe, wpipe = IO.pipe # シリアライズしたデータをパイプに書き込んでいく t = Thread.new do # 10個のオブジェクトを続けて書き込む 10.times {|i| wpipe.write ["object #{i}", i].to_msgpack } wpipe.close end # MessagePack::Unpackerのインスタンスを作る # コンストラクタにIO(ソケットでもファイルでもOK)を渡す pac = MessagePack::Unpacker.new(rpipe) begin # Unpacker#eachでオブジェクトを1つずつ取り出す pac.each {|obj| p obj } rescue EOFError puts "end of file." end
実行すると↓このようにオブジェクトを1つずつ取り出せます:
["object 0", 0] ["object 1", 1] ["object 2", 2] ["object 3", 3] ["object 4", 4] ["object 5", 5] ["object 6", 6] ["object 7", 7] ["object 8", 8] ["object 9", 9] end of file.
パイプやソケット以外に、ファイルでも使えます。このプログラムは、MessagePackでシリアライズされたデータをファイルから読み出し、JSONに変換してから標準出力に出力します:
require 'rubygems' require 'msgpack' require 'json' # シリアライズしたデータを # ファイルに書き出していく File.open("out.mpac", "w") do |f| 10.times {|i| obj = {"time"=>Time.now.to_s, "num"=>i} f.write obj.to_msgpack } end # ファイルを開いて... File.open("out.mpac") do |f| pac = MessagePack::Unpacker.new(f) pac.each {|obj| # データを次々に取り出していく puts obj.to_json # JOSN形式で表示してみる } rescue break end
実行すると↓こうなります:
{"time":"Tue Mar 02 17:20:10 +0900 2010","num":0} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":1} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":2} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":3} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":4} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":5} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":6} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":7} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":8} {"time":"Tue Mar 02 17:20:10 +0900 2010","num":9}
イベント駆動I/OライブラリのEventMachineやRevとの相性もぴったりです:
require 'rubygems' require 'msgpack' require 'json' require 'rev' class MySocket < Rev::TCPSocket def initialize(*arg) super # コネクション毎にデシリアライザを作る @pac = MessagePack::Unpacker.new end # データが届いたら呼ばれる def on_read(data) # デシリアライザにfeedする @pac.feed(data) @pac.each {|obj| # eachでオブジェクトを取り出す on_message(obj) } end def on_message(msg) puts "message received: #{msg.inspect}" write(msg.to_json) # jsonに変換して送り返す end end th = Thread.new do # 8081/tcpでサーバを起動 evloop = Rev::Loop.new evloop.attach Rev::TCPServer.new('0.0.0.0', 8081, MySocket) evloop.run end # 適当にデータを投げてみる sock = TCPSocket.new('0.0.0.0', 8081) sock.write( {'id'=>1, 'msg'=>"this is test"}.to_msgpack ) sock.flush str = sock.sysread(1024) puts "message returned: #{str}"
ここではMessagePackで受信したデータをJSONに変換して返すサーバを実装してみました:
message received: {"msg"=>"this is test", "id"=>1} message returned: {"msg":"this is test","id":1}