【问题标题】:Encoding MessagePack objects containing Node.js Buffers编码包含 Node.js 缓冲区的 MessagePack 对象
【发布时间】:2012-12-05 04:26:21
【问题描述】:

我正在使用node-msgpack 对机器之间传递的消息进行编码和解码。我想做的一件事是将原始 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 本身生成的缓冲区,因此对数据进行了双重打包。为避免混淆,我将其替换为通过读取图像获得的另一个缓冲区,这引发了同样的问题。

【问题讨论】:

  • 原始代码中的“ac”来自哪里? > new Buffer("Hello World!") 给我“”(没有“ac”)
  • 引用上面的 buf = msgpack.pack("Hello World!") :) 这是 msgpack 放在那里的前缀,用于知道以下字节是原始字节并对其长度进行编码。这就是为什么我期待msgpack.unpack(new Buffer(msgpack.unpack(packed).foo)); 返回"Hello World!"
  • 看起来你是双重包装。 (1) 当你执行 buf = msgpack.pack("Hello World!") 和 (2) 当你执行 packed = msgpack.pack(obj) 时,对吧?
  • 好吧,我只是双重打包,因为我想检查使用 msgpack 打包原始缓冲区时的一般情况。如果打包和解包后缓冲区仍然一致,它应该可以工作,对吧? buf 是从压缩数据还是从 JPG 文件中获得的,我猜这无关紧要。

标签: javascript node.js msgpack


【解决方案1】:

当使用除base64hex 之外的任何编码文本解码二进制数据时,会出现缓冲区损坏问题。 node-msgpack 似乎没有接收到。它似乎会自动尝试使用“utf-8”,这会不可逆转地破坏缓冲区。他们必须做类似的事情,所以我们最终不会得到一堆缓冲区对象而不是普通字符串,这主要是我们的 msgpack 对象通常由什么组成的。


编辑

上面显示有问题的三个字节代表 UTF-8 Replacement Character。快速测试表明,这个字符是为了替换开头无法识别的0x89 字节:

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

来自node-msgpackThis line of C++ code 对此行为负责。当截获给编码器的数据结构中的Buffer 实例时,它只是将其绑定转换为String,相当于执行buffer.toString(),默认情况下假定UTF-8 编码,用上面的替换每个无法识别的字符。

下面建议的替代模块通过将缓冲区保留为原始字节来解决此问题,而不是尝试将其转换为字符串,但这样做与其他 MessagePack 实现不兼容。如果兼容性是一个问题,解决此问题的方法是提前使用二进制安全编码(如binarybase64hex)对非UTF-8 缓冲区进行编码。 base64hex 将不可避免地显着增加数据的大小,但会保持一致,并且在通过 HTTP 传输数据时使用起来最安全。如果大小也是一个问题,那么通过像Snappy 这样的流式压缩算法传送 MessagePack 结果可能是一个不错的选择。


结果是另一个模块,msgpack-js(这是一个用 javascript 编写的 msgpack 编码器/解码器),保留原始二进制数据,因此解决了上述问题。他是这样做的:

我稍微扩展了格式以允许对未定义和 Buffer 实例进行编码和解码。

这需要三个以前标记为“保留”的新类型代码。此更改意味着使用这些新类型将使您的序列化数据与其他没有相同扩展名的消息包实现不兼容。

作为奖励,它也比前面提到的基于 C++ 扩展的模块具有更高的性能。它也更年轻,所以可能没有经过彻底的测试。时间会证明一切。这是我根据one that was included in node-msgpack 进行的快速基准测试的结果,比较了两个库(以及本机 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 的性能仍然要好得多。

【讨论】:

    猜你喜欢
    • 2014-12-30
    • 1970-01-01
    • 2011-08-25
    • 2020-05-02
    • 2015-05-21
    • 2020-07-13
    • 2012-04-24
    • 2013-07-09
    • 1970-01-01
    相关资源
    最近更新 更多