如何使用Python优雅地发送/接收大型C结构?
我已经开始编写Python 3.x客户端应用程序了。 服务器应用程序已经存在并用C语言编写。服务器提供了一个C头文件,其中包含两个用于通过UDP发送和接收数据的结构的定义(我正在使用Python的socket
模块)。 问题是C结构非常大(每个大约200个元素)。 如果我使用Python的struct
模块来打包/解包数据,那么一个不那么优雅的解决方案就是手动打包/解包200个元素,如:
struct.pack('H...I', data1, ..., data200)
此外,我希望能够使用类似C的语法访问Python中的接收/发送元素。 例如,如果我在C服务器端
send.data.pos = pos;
如果我可以像这样访问Python客户端中的pos
变量,那将是很好的(最自然的):
pos = recv.data.pos
请注意,问题不在于如何从头文件中自动编写Python结构,就像在这个线程中一样(我在Python中逐个编写每个结构字段没有问题),而是什么是最好的组织方式Python中的数据(例如在类中,使用字典等),这将允许我利用Pythonfunction并使代码更简单,数据易于访问(我宁愿只使用Python标准模块,也不使用外部软件)。 实现这一目标最优雅的方法是什么?
试试这个 – 适用于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)
输出:
Packet1(u1=241, u2=242, u4=244) 244
您可以编写一个具有成员函数的类,使用struct.pack
等将数据打包/解包到类属性中。
我建议看看Construct 。 但我认为它还没有被移植到Python 3.x. 构造已经中断了一段时间,但最近被新开发人员接受了,所以也许很快就可以支持Python 3.x.
您可以使用dpkt作为访问数据包数据的简单方法。 看看这里的用法示例。 举个简单的例子:
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)