5

node-msgpackを使用して、マシン間で受け渡されるメッセージをエンコードおよびデコードしています。私ができるようにしたいことの1つは、生のBufferデータをオブジェクトにラップし、それをMessagepackでエンコードすることです。

msgpack = require('msgpack')
buf = <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 ...>
obj = {foo: buf}
packed = msgpack.pack(obj)

上記の例では、オブジェクトにネストされたバッファの生のバイトに対して整合性チェックを実行したいと思いました。だから、そのbufように得られました:

var buf = fs.readFileSync('some_image.png');

完璧な世界では、私は得たでしょう:

new Buffer(msgpack.unpack(packed).foo);

#> <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 ...>

代わりに、私はいくつかの乱数で終わります。もう少し掘り下げてみると、次のような好奇心があります。

enc = 'ascii'
new Buffer(buf.toString(enc), enc)
#> <Buffer *ef bf bd* 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 ...>

buf
#> <Buffer *89* 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 02 00 ...>

最初のバイトが問題です。運が悪かったので、別のエンコーディングを使用してみました。ここで何が起こっているのでしょうか。また、問題を回避するために何ができるでしょうか。

編集:

元々、これbufはmsgpack自体で生成したバッファーであり、データを二重にパックしていました。混乱を避けるために、画像を読み取って取得した別のバッファに置き換えたところ、同じ問題が発生しました。

4

1 に答える 1

5

base64バッファ破損の問題は、とを除く任意のエンコーディングテキストを使用してバイナリデータをデコードするときに発生しますhexnode-msgpackによって取得されていないようです。バッファを不可逆的に台無しにする「utf-8」を自動的に使用しようとしているようです。彼らはそのようなことをしなければならなかったので、通常の文字列の代わりにバッファオブジェクトの束になってしまうことはありません。これは主に私たちのmsgpackオブジェクトが通常作られているものです。


編集

問題があると上に示された3バイトは、UTF-8置換文字を表します。簡単なテストでは、この文字が最初に認識できない0x89バイトを置き換えることであったことが示されています。

new Buffer((new Buffer('89', 'hex')).toString('utf-8'), 'utf-8')
//> <Buffer ef bf bd>

node-msgpackからのC++コードのこの行は、この動作の原因です。Bufferエンコーダーに与えられたデータ構造内のインスタンスをインターセプトするとき、それは単にそれをにバインド的に変換します。これは、デフォルトでエンコードを想定し、認識できないすべての文字を上記に置き換えてString実行するのと同じです。buffer.toString()UTF-8

以下に提案する代替モジュールは、バッファを文字列に変換しようとせずにrawバイトのままにすることでこれを回避しますが、そうすることで他のMessagePack実装と互換性がありません。互換性が懸念される場合、これを回避するには、、、などのバイナリセーフエンコーディングを使用して非バッファUTF-8を事前にエンコードします。または、必然的にデータのサイズが大幅に増加しますが、一貫性が保たれ、HTTPを介してデータを転送するときに最も安全に使用できます。サイズも問題になる場合は、 Snappyなどのストリーミング圧縮アルゴリズムを介してMessagePackの結果をパイプ処理することをお勧めします。binarybase64hexbase64hex


別のモジュールであるmsgpack-js(すべてjavascriptで記述されたmsgpackエンコーダー/デコーダー)は、生のバイナリデータをそのまま残すため、上記の問題を解決します。彼がそれをした方法は次のとおりです。

フォーマットを少し拡張して、未定義のバッファインスタンスのエンコードとデコードを可能にしました。

これには、以前に「予約済み」とマークされていた3つの新しいタイプコードが必要でした。この変更は、これらの新しいタイプを使用すると、シリアル化されたデータが、同じ拡張子を持たない他のメッセージパックの実装と互換性がなくなることを意味します。

ボーナスとして、前述のC++拡張ベースのモジュールよりもパフォーマンスが高くなります。また、はるかに若いので、十分にテストされていない可能性があります。時が教えてくれる。これは、node-msgpackに含まれているものに基づいて、2つのライブラリ(およびネイティブJSONパーサー)を比較した、私が行った簡単なベンチマークの結果です。

node-msgpack pack:   3793 ms
node-msgpack unpack: 1340 ms

msgpack-js pack:   3132 ms
msgpack-js unpack: 983 ms

json pack:   1223 ms
json unpack: 483 ms

そのため、ネイティブのjavascript msgpackデコーダーを使用するとパフォーマンスが向上しますが、JSONの方がはるかにパフォーマンスが高くなります。

于 2012-12-22T01:46:28.250 に答える