如何使用Python优雅地发送/接收大型C结构?

2024-05-17 04:04:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经开始编写Python3.x客户机应用程序。服务器应用程序已经存在,并且是用C编写的。服务器提供了一个C头文件,其中包含两个用于通过UDP发送和接收数据的结构的定义(我使用的是Python的socket模块)。 问题是C结构相当大(每个大约200个元素)。如果我使用Python的struct模块来打包/解包数据,一个不那么优雅的解决方案是手动打包/解包200个元素,比如:

struct.pack('H...I', data1, ..., data200)

此外,我希望能够使用类似C的语法访问Python中的接收/发送元素。例如,如果我在C服务器端

^{pr2}$

如果我可以像下面这样访问Python客户端中的pos变量,那就太好了(最自然):

pos = recv.data.pos

请注意,问题是如何从头文件自动用Python编写结构,就像在thisthread中一样(我在Python中逐个编写每个结构字段没有问题),而是在Python中组织数据的最佳方法是什么(例如在类中,使用字典,这将使我能够利用Python的特性,使代码更简单,数据也更易于访问(我宁愿只使用Python标准模块,不使用外部软件)。实现这一目标最优雅的方法是什么?在


Tags: 模块数据方法pos服务器应用程序元素客户机
3条回答

您可以使用struct.pack等方法编写一个具有成员函数的类来将数据打包到类属性中/从类属性中解包

我建议调查一下Construct。但我认为它还没有被移植到python3.x中。Construct暂停了一段时间,但最近被一个新的开发人员发现了,所以它可能很快就能支持python3.x。在

在2.7和3.2上试试这个。在

脚本:

import struct, collections

class CStruct(object):

    def __init__(self, typename, format_defn, lead_char="!"):
        self.names = []
        fmts = [lead_char]
        for line in format_defn.splitlines():
            name, fmt = line.split()
            self.names.append(name)
            fmts.append(fmt)
        self.formatstr = ''.join(fmts)
        self.struct = struct.Struct(self.formatstr)
        self.named_tuple_class = collections.namedtuple(typename, self.names)

    def object_from_bytes(self, byte_str):
        atuple = self.struct.unpack(byte_str)
        return self.named_tuple_class._make(atuple)

if __name__ == "__main__":
    # do this once
    pkt_def = """\
        u1 B
        u2 H
        u4 I"""
    cs = CStruct("Packet1", pkt_def)
    # do this once per incoming packet
    o = cs.object_from_bytes(b"\xF1\x00\xF2\x00\x00\x00\xF4")
    print(o)
    print(o.u4)

输出:

^{pr2}$

您可以使用dpkt作为访问数据包数据的简单方法。查看here中的用法示例。举个简单的例子:

class Foo(dpkt.Packet):
    __hdr__ = (('type', 'B', 0),
               ('size', 'B', 0))

data = get_udp_message()
foo = Foo(data)
if foo.size != len(data):
    print "Bad size in header"
if foo.type == 3:
    parse_payload(foo.data)

相关问题 更多 >