MsgPack在python中打包超过32个字符的字符串值

时间:2013-10-19 13:08:37

标签: python objective-c python-2.7 msgpack

我正在使用MessagePack开发客户端SDK。我需要在java,ObjC和python中开发客户端,而我的服务器是在java中。我对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>

如果我错过了一些显而易见的事情,我很抱歉..寻找任何变通办法或建议,因为我被打了一天以上..

提前致谢。

1 个答案:

答案 0 :(得分: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

对这个问题感兴趣,我用Google搜索了MsgPack的规格并遇到了this

现在事情越来越清晰。

  • \x81表示以下是单元素地图。
  • \xA7表示以下是七个字符的字符串。
  • api_key是七个字符的字符串。

到目前为止,这么好。现在差异开始了:

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

所以看起来所有序列化都是正确的,但是你使用的解串器无法处理Python序列化器使用的str8数据类型。用于格式化更改的implementation guidelines状态,并非所有版本都支持str8,因此序列化程序应提供不带它的兼容模式。但是,Python的msgpack包不会。

更新bug report后几个小时,msgpack-Python的开发人员添加了一个兼容性开关,强制Python创建str16序列化,而不是str8。做得好!