1

MessagePack を使用して Delphi でレコードをシリアル化し、ZeroMQ TCP プロトコルを使用して Python サーバーに送信しようとしています。

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

サーバー側でデシリアライズするのに問題があります。なぜこれが起こっているのですか?ある種のエンコーディングの問題ですか?ありがとう!

更新 #1:

私は、 www.msgpack.orgで推奨されているメッセージパック ライブラリ「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]

何故ですか?

4

1 に答える 1

1

パックされたデータが無効のようです。

>>> パケット = { "DataType": 1, "data": "{\"メジャー\":1,\"マイナー\":0,\"ビルド\":2}"}
>>> umsgpack.packb(パケット)
b'\x82\xa4data\xbf{"メジャー":1,"マイナー":0,"ビルド":2}\xa8DataType\x01'

最初のバイトは、仕様\x82でわかるように、2 エントリのフィックスマップです。

パックされたデータにはその情報が欠落しており、fixstr に直接起動します。そうです、Delphi ベースのパッカーと Python ベースのアンパッカーの間に不一致がある可能性があります。ただし、リポジトリから最新の qmsgpack を使用して Delphi コードを取得すると、次のバイトが生成されます。

82A8446174615479706501A464617461
BF7B226D616A6F72223A312C226D696E
6F72223A312C226275696C64223A317D

これを Python の bytes オブジェクトに変換しましょう。次のようになります。

b'\x82\xa8DataType\x01\xa4data\xbf{"メジャー":1,"マイナー":1,"ビルド":1}'

さて、それはあなたが報告したものとはかなり異なります。そして、umsgpackそれをうまく解凍できます。最初のバイトは\x82、2 エントリのフィックスマップであり、予想どおりであることに注意してください。はい、エントリの順序が異なりますが、それで問題ありません。マップの順序は重要ではありません。

そのため、Delphi で qmsgpack を使用してエンコードし、Python で umsgpack を使用してデコードすることができました。これは、この問題が実際には送信にあることを示唆しています。オフバイワンエラーが発生したように見えます。バイト 0 から N-1 を送信する代わりに、バイト 1 から N が送信されました。受信したデータの誤った末尾のゼロに注意してください。


コメントでは、dataフィールドが JSON としてコーディングされ、文字列として渡されていることがわかります。しかし、MessagePack を使用してそのデータをエンコードした方がよいでしょう。だからここに何をすべきかです:

  1. Delphi コードで、dataフィールドのタイプを からstringに変更しTBytesます。これは、そこにバイト配列を配置するためです。
  2. 次のように、を使用してdataフィールドに入力します。Encodepacket.data := lvMsg.Encode
  3. Python 側では、展開dataすると整数の配列であることがわかります。それをバイトに変換してから解凍します: umsgpack.unpackb(bytes(data)).
于 2014-09-15T11:14:21.453 に答える