Неуказанные длины в байтах в Python - PullRequest
4 голосов
/ 05 марта 2012

Я пишу клиент для приложения P2P в минуту, и спецификация протокола говорит, что заголовок для каждого пакета должен иметь каждое поле с определенной длиной байта, например:

Version: 1 Byte 
Type: 1 Byte
Length: 2 Bytes
And then the data

У меня есть способ упаковки и распаковки полей заголовка (я думаю) следующим образом:

packed = struct.pack('cch' , '1' , '1' , 26)

Это создает заголовок для пакета с длиной данных 26, но когда дело доходит до распаковкиданные Я не уверен, как получить остальные данные потом.Для распаковки нужно знать размер всех полей, разве я что-то упустил?Я предполагаю, что для упаковки данных я бы использовал индикатор формата 'cch26s', означающий:

1 Byte char
1 Byte char
2 Byte short
26 Byte char array

Но как мне распаковать данные, когда я не знаю, сколько данных будет сначала включено в пакет?

Ответы [ 2 ]

3 голосов
/ 05 марта 2012

При описании протокола вы должны сначала распаковать первые четыре байта и извлечь Length (16-битное целое число).Это говорит вам, сколько байтов нужно распаковать на втором шаге.

version, type, length = struct.unpack("cch", packed[:4])
content, = struct.unpack("%ds" % length, packed[4:])

Это если все проверено.unpack () требует, чтобы упакованный буфер содержал ровно столько данных, сколько вы распаковываете.Также проверьте, включены ли 4 байта заголовка в счетчик длины.

2 голосов
/ 05 марта 2012

Вы можете определить количество символов для распаковки, проверив len(data).

Вот вспомогательная функция, которая сделает это за вас:

def unpack(fmt, astr):
    """
    Return struct.unpack(fmt, astr) with the optional single * in fmt replaced with
    the appropriate number, given the length of astr.
    """
    # http://stackoverflow.com/a/7867892/190597
    try:
        return struct.unpack(fmt, astr)
    except struct.error:
        flen = struct.calcsize(fmt.replace('*', ''))
        alen = len(astr)
        idx = fmt.find('*')
        before_char = fmt[idx-1]
        n = (alen-flen)/struct.calcsize(before_char)+1
        fmt = ''.join((fmt[:idx-1], str(n), before_char, fmt[idx+1:]))
        return struct.unpack(fmt, astr)

Вы можете использовать ее следующим образом:

unpack('cchs*', data)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...