Как элегантно отправить / получить большую структуру C, используя Python? - PullRequest
3 голосов
/ 18 мая 2011

Я начал писать клиентское приложение Python 3.x. Серверное приложение уже существует и написано на C. Сервер предоставляет файл заголовка C с описанием двух структур, используемых для отправки и получения данных по UDP (я использую модуль Python socket). Проблема в том, что структуры C довольно большие (около 200 элементов в каждой). Если я использую модуль Python struct для упаковки / распаковки данных, не слишком элегантным решением будет ручная упаковка / распаковка 200 элементов, например:

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

Кроме того, я хочу иметь возможность доступа к полученным / отправленным элементам в Python с использованием синтаксиса, подобного С. Например, если я делаю на стороне сервера C

send.data.pos = pos;

было бы неплохо (наиболее естественно), если бы я мог получить доступ к переменной pos на стороне клиента Python следующим образом:

pos = recv.data.pos

Обратите внимание, что вопрос , а не , как автоматически записать структуру в Python из файла заголовка, как в этом потоке (у меня нет проблем при написании каждого поля структуры по одному один в Python), а точнее, какой будет лучший способ организовать данные в Python (например, в классах, с использованием словарей и т. д.), который позволит мне использовать функции Python и упростит код, а данные станут легко доступны ( Я бы предпочел использовать только стандартные модули Python, без внешнего программного обеспечения). Каков будет самый элегантный способ добиться этого?

Ответы [ 3 ]

1 голос
/ 18 мая 2011

Попробуйте это - работает на 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
1 голос
/ 18 мая 2011

Возможно, вы сможете использовать 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)
1 голос
/ 18 мая 2011

Вы можете написать класс, который имеет функции-члены для упаковки / распаковки данных в / из атрибутов класса, используя struct.pack и т. Д.

Я бы посоветовал изучить Конструкт .Но я не думаю, что он был портирован на Python 3.x.Некоторое время Construct находился в состоянии перерыва, но недавно был подхвачен новым разработчиком, поэтому, возможно, он вскоре сможет поддерживать Python 3.x.

...