在Delphi中使用MessagePack序列化用户定义类型时可能出现的编码问题?

时间:2014-09-14 20:27:34

标签: python json delphi encoding messagepack

我正在尝试使用MessagePack序列化Delphi中的Record,然后使用ZeroMQ TCP协议将其发送到Python服务器。

b'\xa8DataType\x01\xa4data\xbf{"major":1,"minor":0,"build":2}\x00'

我在服务器端反序列化时遇到问题。任何想法为什么会这样?是某种编码问题吗?谢谢!

更新#1:

我使用www.msgpack.org推荐的messagepack库“QMsgPack”这里有一些Delphi代码。我的用户定义了记录和枚举:

Version = Record
    major : Integer;
    minor : Integer;
    build : Integer;
end;

TDataType = (dtUnset, dtVersion, dtEntityDescription, dtEntityDescriptionVector, dtEntityState, dtEntityStateVector, dtCommandContinue, dtCommandComplete);

TPacket = Record
    DataType : TDataType;
    data : string;
end;

序列化对象的代码:

begin
    dmVersion.major := 1;
    dmVersion.minor := 1;
    dmVersion.build := 1;

    lvMsg := TQMsgPack.Create;
    lvMsg.FromRecord(dmVersion);

    lvMsgString := lvMsg.ToString();

    packet.DataType := dtVersion;
    packet.data := lvMsgString;
    lvMsg.Clear;
    lvMsg.FromRecord(packet);
    lvbytes:=lvMsg.Encode;
    ZeroMQ.zSendByteArray(skt, lvbytes);

然后我尝试反序列化python服务器中收到的字节数组,如下所示:

b'\xa8DataType\x01\xa4data\xbf{"major":1,"minor":0,"build":2}\x00'

使用umsgpack.unpack(),然后在结果中打印出结果,如下所示:

packet_packed = command.recv()

# Unpack the packet
umsgpack.compatibility = True
packet = umsgpack.unpackb( packet_packed )
print (packet) 
for item in packet:
    print (item)

这就是我在屏幕上打印出来的内容:

b'DataType'
68
97
116
97
84
121
112
101

我希望这有帮助!谢谢!

更新#2

这是python端的一些服务器代码。 VDS_PACKET_VERSION是一个设置为1的常量int。

    # Make sure its a version packet
    if VDS_PACKET_VERSION == packet[0]:

        # Unpack the data portion of the packet
        version = umsgpack.unpackb( packet[1] )

        roster = []
        if ( VDS_VERSION_MAJOR == version[0] ) and ( VDS_VERSION_MINOR == version[1] ) and ( VDS_VERSION_BUILD == version[2] ):
            dostuff()

使用当前的序列化对象

b'\x82\xa8DataType\x01\xa4data\xbf{"major":1,"minor":1,"build":1}'

我得到了

KeyError: 0 on packet[0]

为什么?

1 个答案:

答案 0 :(得分:1)

打包数据似乎无效。

>>> packet = { "DataType": 1, "data": "{\"major\":1,\"minor\":0,\"build\":2}"}
>>> umsgpack.packb(packet)
b'\x82\xa4data\xbf{"major":1,"minor":0,"build":2}\xa8DataType\x01'

第一个字节是\x82,正如specification中所见,它是一个两个条目的修复映射。

您的打包数据缺少该信息,并直接启动到fixstr。所以,是的,基于Delphi的打包程序和基于Python的解包程序之间可能存在不匹配。但是,当我使用你的Delphi代码,使用repo中最新的qmsgpack时,它产生以下字节:

82A8446174615479706501A464617461
BF7B226D616A6F72223A312C226D696E
6F72223A312C226275696C64223A317D

让它将其转换为Python字节对象。它看起来像这样:

b'\x82\xa8DataType\x01\xa4data\xbf{"major":1,"minor":1,"build":1}'

现在,这与你举报的内容截然不同。 umsgpack可以解压缩它。请注意,第一个字节是\x82,两个条目的fixmap,正如预期的那样。是的,条目的顺序不同,但这很好。订单对地图而言并不重要。

所以,我已经能够在Delphi中使用qmsgpack进行编码,并使用Python中的umsgpack进行解码。这表明这个问题确实存在于传播中。它看起来好像有一个一个一个错误。不是发送字节0到N-1,而是发送了字节1到N.请注意接收数据中的虚假尾随零。


在评论中,您认为data字段被编码为JSON并作为字符串传递。但是你宁愿使用MessagePack编码数据。所以这是做什么的:

  1. 在Delphi代码中,将data字段的类型从string更改为TBytes。那是因为我们要在那里放一个字节数组。
  2. 使用data填充Encode字段,如下所示:packet.data := lvMsg.Encode
  3. 在Python方面,当你解包data时,你会发现它是一个整数数组。将其转换为字节,然后解压缩:umsgpack.unpackb(bytes(data))