1

以下はCからの構造体であり、Pythonに変換しようとしており、ソケットを使用して構造体を送信しています

子:

        struct CommandReq
        {
            char    sMark[6];  //start flag\r\n*KW
            short   nPackLen;  //packet length
            short   nFlag;     //command ID 0x0002
            int     nGisIp;    //GIS port
            short   nPort;     //GIS Port
            char    sData[50]; //command string
            char    sEnd[2];   //end flag "\r\n"
        };
        //source code
        CommandReq stResq;
        memset(&stResq, 0, sizeof(stResq));
        sprintf(stResq.sMark, "\r\n%s", "*KW");
        stResq.nFlag = 0x0002;
        stResq.nPackLen = sizeof(stResq);
        stResq.nGisIp = 0;
        stResq.nPort = 0;
        strcpy(stResq.sData, "*KW,CC09C00001,015,080756,#");
        strncpy(stResq.sEnd, "\r\n", 2);

namedtuple を使用して Python 構造体を作成し、ソケットを使用してこの構造体を送信します。しかし残念ながら失敗。

パイソン:

from collections import namedtuple
MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")

編集、以下の回答への返信

把握した後、python 3.x を追加する必要があります string .encode("ascii")

      format_ = "6shhih50s2s"
      MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
      tuple_to_send = MyStruct(sMark="\r\n{}".format("*KW").encode("ascii"), 
                 nPackLen=struct.calcsize(format_),
                 nFlag=0x0002,
                 nGisIp=0,
                 nPort=0,
                 sData= "*KW,NR09G05133,015,080756,#".encode("ascii"),
                 sEnd="\r\n".encode("ascii"))
      string_to_send = struct.pack(format_, *tuple_to_send._asdict().values()
      socket.sendto(string_to_send, self.client_address)

追加の質問

以下は、構造体で送信されているパケットです

format_ = "6shhih50s2s" //total bytes should be 68 bytes?
    0d0a2a4b5700 //6 char \r\n*KW
    4600 // packet length 70 bytes
    0200 //command ID 0x0002,short 2 bytes
    00000000 //GIS port is integer 4 bytes
    0000 //GIS Port short 2 bytes
    0000 //unknown??what is this?
    2a4b572c4e5230394730353133332c3031352c3038303735362c230000000000000000000000000000000000000000000000 //sData[50] char 50 bytes
    0d0a //sEnd 2 char,2 bytes

未知の 2 バイトはどうして??

4

1 に答える 1

2

namedtuple は、実際には c-struct に匹敵するものではありません。構造体の使用に慣れている場合は、struct-moduleを見て、構造化された情報を文字列に変換できます。

一般に、Pythonistaはシリアル化にpickle-moduleを使用することを好みます。

from collections import namedtuple
import pickle # or cPickle, it's faster
MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")

tuple_to_send = MyStruct(sMark="abcdef", nPackLen=...)
string_to_send = pickle.dumps(tuple_to_send)

pickleピクルスは、との 2 種類の味がありcPickleます。後者は高速ですが、CPython (ほとんどのプログラマーが使用) でのみ使用できますが、pickle は Jython、IronPython などでも使用できます。

構造体に固執したい場合 (たとえば、反対側がこの形式を期待しているため)、形式文字列は次のようになります。

format_ = "6shhih50s2s"

したがって、次のことができます。

import struct
from collections import namedtuple

format_ = "6shhih50s2s"

MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
tuple_to_send = MyStruct(sMark="\r\n{}".format("*KW"), 
                     nPackLen=struct.calcsize(format_),
                     nFlag=0x0002,
                     nGisIp=0,
                     nPort=0,
                     sData= "*KW,NR09G05133,015,080756,#",
                     sEnd="\r\n")


string_to_send = struct.pack(format_, *tuple_to_send._asdict().values())

ところで:名前付きタプルは不変です。つまり、できません

tuple_to_send.sMark = "bcdefg"

一部のプロパティを変更します。このような動作が必要な場合は、クラスを作成する必要があります。

編集

Python 3 では、文字列の扱いが変更されました。Unicode からバイトへの変換を実行する必要があります。

import struct
from collections import namedtuple

format_ = "6shhih50s2s"

MyStruct = namedtuple("MyStruct", "sMark nPackLen nFlag nGisIp nPort sData sEnd")
tuple_to_send = MyStruct(sMark="\r\n{}".format("*KW").encode("ascii"), 
                     nPackLen=struct.calcsize(format_),
                     nFlag=0x0002,
                     nGisIp=0,
                     nPort=0,
                     sData= "*KW,NR09G05133,015,080756,#".encode("ascii"),
                     sEnd=b"\r\n")


string_to_send = struct.pack(format_, *tuple_to_send._asdict().values())
于 2013-01-31T07:45:09.930 に答える