0

我正在使用 MessagePack 开发客户端 SDK。当我的服务器在 java 中时,我需要在 java、ObjC 和 python 中开发客户端。我对 java 和 ObjC msgpack 库没有任何问题,但是在 python 中,当我打包一个字符串值超过 31 个字符的字典时,打包的数据不会以其他语言解包。尝试在 python 中解压同样的工作很好,只要字符串长度小于 32,互操作性也很好。下面是一个失败的python示例..

myPacket = {u"api_key":u"ad09739ac168ff2a199fb24eb4e24db8"}
msgPackedPacket = umsgpack.packb(myPacket)

为此生成的二进制数据是

<81a76170 695f6b65 79d92061 64303937 33396163 31363866 66326131 39396662 32346562 34653234 646238>

而如果我在 ObjC 中隐藏具有相同键值的字典,我会得到

<81a76170 695f6b65 79da0020 61643039 37333961 63313638 66663261 31393966 62323465 62346532 34646238>

ObjC 结果解包很好,python 不会..您可以注意到来自 ObjC 的数据中的 2 个额外字节。

一个正常工作的例子如下

myPacket = {u"api_key":u"ad09739ac168ff2a199fb24eb4e24d"}  

这里的字符数= 30..我在python中得到以下字节

<81a76170 695f6b65 79be6164 30393733 39616331 36386666 32613139 39666232 34656234 65323464>

对于 ObjC,我得到以下字节..

<81a76170 695f6b65 79be6164 30393733 39616331 36386666 32613139 39666232 34656234 65323464>

如果我错过了一些明显的东西,我很抱歉.. 寻找任何解决方法或建议,因为我被打击了超过一天..

提前致谢。

4

1 回答 1

3

查看十六进制字符串对哪些字符进行编码时,您可以看到第一个解码为

'\x81\xa7api_key\xd9 ad09739ac168ff2a199fb24eb4e24db8'  # Python's version

而第二个解码为

'\x81\xa7api_key\xda\x00 ad09739ac168ff2a199fb24eb4e24db8'  # ObjC's version

第三个 30 字节长的字符串,解码为

'\x81\xa7api_key\xbead09739ac168ff2a199fb24eb4e24d'     # both versions

对这个问题很感兴趣,我搜索了 MsgPack 的规格并发现了这个.

现在事情越来越清楚了。

  • \x81表示以下是单元素映射。
  • \xA7表示下面是一个七字符的字符串。
  • api_key是那个七个字符的字符串。

到目前为止,一切都很好。现在差异开始了:

  • \xd9表示后面有一个str8字符串。后面的字节\xd9\x20( hex 20 == dec 32 == ASCII space)。它表示该字符串的长度 (32)。这就是 Python 正确使用的方法,因为str8它可用于长度不超过 255 个字符的字符串。
  • \xda表示后面有一个str16字符串。以下两个字节是\x00\x20hex 0020== dec 32,如前所述)。它们还表示以下字符串的长度(再次为 32)。显然,这就是 ObjC 所做的。从规范的角度来看,这同样合法,只是有点浪费(一个浪费的字节)。
  • 对于少于 32 个字符的字符串,两种实现都使用fixstr在位域中编码长度为 1-31 个字符的类型,该位域101xxxxx变成\xbe30 个字符的字符串 ( bin 10111110)。

所以看起来所有的序列化都是正确的,但是您使用的反序列化器无法处理str8Python 的序列化器使用的数据类型。实施指南指出,由于格式更改,并非所有版本都支持,str8因此序列化程序应提供没有它的兼容模式。但是, Python 的msgpack包没有。

更新:在错误报告后几个小时,开发人员msgpack-Python添加了一个兼容性开关,以强制 Python 创建str16序列化而不是str8. 做得好!

于 2013-10-19T13:22:52.673 回答