【问题标题】:Python : Socket Sending Struct(having C stuct as Example)Python:套接字发送结构(以 C 结构为例)
【发布时间】:2013-01-31 07:33:12
【问题描述】:

下面是来自 C 的结构,我正在尝试转换为 Python, 并使用 Socket 发送结构体

C:

        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 结构,并使用套接字发送这个结构。 但遗憾的是失败了。

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个未知字节怎么来的??

【问题讨论】:

    标签: python c sockets struct python-3.x


    【解决方案1】:

    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)
    

    泡菜有两种口味,picklecPickle。后者更快,但仅在 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())
    

    顺便说一句:namedtuples 是不可变的,也就是说,你不能这样做

    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())
    

    【讨论】:

    • sData 是 50 chac?这 50 怎么办?
    • 看看this table。这里解释了 struct-module 的所有格式规范。这有帮助吗?
    • @Thorsen Kranz ,不,它没有帮助。如何在 namedtuple 或某处声明 chac[50]?
    • Python 不知道字符数组。我准备一个使用struct的例子。
    • 在 Python 3 中,字符串处理方式发生了变化。您尝试将 unicode-strings 放在需要字节字符串的位置。我建议在结构的每个字符串之后放置一个.encode("ascii") - 尽管我不知道这是否是您想要的。可能,您应该确保您的数据从一开始就是字节。
    猜你喜欢
    • 2016-06-06
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 2010-11-22
    • 2015-01-02
    相关资源
    最近更新 更多