Проблема с использованием struct.pack и struct.unpack

В вашем классе вы можете перегрузить символ "& lt;" оператора.

class MyClass
{
  bool operator <(const MyClass& rhs)
  {
    return this->key < rhs.key;
  }
}
1
задан martineau 1 March 2019 в 20:04
поделиться

2 ответа

Если вы хотите, чтобы struct.unpack возвратил данные, которые вы передали struct.pack, то аргумент, который вы передаете struct.unpack, должен быть объектом, который возвращается из struct.pack. Прямо сейчас вы предоставляете ему пустой байт-массив, поэтому вы возвращаете пустые данные.

Одним из возможных решений является передача упакованных данных в качестве аргумента _packet.unpack, который затем передается в struct.unpack.

import struct


class _packet:

    def __init__(self, payload):  
        self.version = 1
        self.syn = False
        self.fin = False
        self.reset = False
        self.hasOpt = False
        self.ack = 0
        self.payload = payload
        return

    def pack(self):
        return struct.pack('????i' + str(len(self.payload)) + 's', self.syn, self.fin, self.reset, self.hasOpt,self.ack, bytes(self.payload, 'utf-8'))

    def unpack(self, data):
        header_size = 8 #four one-byte bools and one four-byte int
        return struct.unpack('????i' + str(len(packed_data)-header_size) + 's', data)

def main():
    packet = _packet("Hello")
    packet.ack = 249
    packet.syn = True
    packet.fin = True
    packet.reset = True
    packedData = packet.pack()
    print(packedData)
    unpackedData = packet.unpack(packedData)
    print(unpackedData)

if __name__== "__main__":
  main()

Или, возможно, вы бы предпочли назначить упакованные данные как атрибут экземпляра _packet, поэтому вызывающей стороне не нужно предоставлять никаких аргументов.

import struct


class _packet:

    def __init__(self, payload):  
        self.version = 1
        self.syn = False
        self.fin = False
        self.reset = False
        self.hasOpt = False
        self.ack = 0
        self.payload = payload

        self.packed_data = None

    def pack(self):
        self.packed_data = struct.pack('????i' + str(len(self.payload)) + 's', self.syn, self.fin, self.reset, self.hasOpt,self.ack, bytes(self.payload, 'utf-8'))
        return self.packed_data

    def unpack(self):
        header_size = 8 #four one-byte bools and one four-byte int
        return struct.unpack('????i' + str(len(packed_data)-header_size) + 's', self.packed_data)

def main():
    packet = _packet("Hello")
    packet.ack = 249
    packet.syn = True
    packet.fin = True
    packet.reset = True
    packedData = packet.pack()
    print(packedData)
    unpackedData = packet.unpack()
    print(unpackedData)

if __name__== "__main__":
  main()

Лично я бы сделал unpack методом класса, поскольку вам не нужно создавать экземпляр _packet для десериализации некоторых байтов в новый объект _packet. Я бы также сделал атрибуты объекта необязательно устанавливаемыми во время инициализации, поэтому вам не нужно присваивать им индивидуально в main.

import struct


class _packet:

    def __init__(self, payload, **kwargs):  
        self.version = 1
        self.syn = kwargs.get("syn", False)
        self.fin = kwargs.get("fin", False)
        self.reset = kwargs.get("reset", False)
        self.hasOpt = kwargs.get("hasOpt", False)
        self.ack = kwargs.get("ack", 0)
        self.payload = payload

    def pack(self):
        return struct.pack('????i' + str(len(self.payload)) + 's', self.syn, self.fin, self.reset, self.hasOpt,self.ack, bytes(self.payload, 'utf-8'))

    #optional: nice string representation of packet for printing purposes
    def __repr__(self):
        return "_packet(payload={}, syn={}, fin={}, reset={}, hasOpt={}, ack={})".format(self.payload, self.syn, self.fin, self.reset, self.hasOpt, self.ack)

    @classmethod
    def unpack(cls, packed_data):
        header_size = 8 #four one-byte bools and one four-byte int
        syn, fin, reset, hasOpt, ack, payload = struct.unpack('????i' + str(len(packed_data)-header_size) + 's', packed_data)
        return cls(payload, syn=syn, fin=fin, reset=reset, hasOpt=hasOpt, ack=ack)
def main():
    packet = _packet("Hello", ack=249, syn=True, fin=True, reset=True)
    packedData = packet.pack()
    print(packedData)
    unpackedData = _packet.unpack(packedData)
    print(unpackedData)

if __name__== "__main__":
  main()
0
ответ дан Kevin 1 March 2019 в 20:04
поделиться

Несколько замечаний:

  1. Вы можете предварительно создать объект Struct для упаковки и распаковки заголовка
  2. Полезную нагрузку легче упаковать и распаковать отдельно. из шапки. Он может быть добавлен к упакованному заголовку и извлечен из пакета, используя нарезку.
  3. unpack должен быть методом класса, который принимает объект bytes и возвращает экземпляр Packet.
  4. Создание этого класса данных позволяет избежать написания большого количества шаблонов для метода __init__.
<час>
from dataclasses import dataclass
from typing import ClassVar
import struct

@dataclass
class Packet:

    header : ClassVar[struct.Struct] = struct.Struct('????i')
    payload: str
    syn: bool = False
    fin: bool = False
    reset: bool = False
    has_opt: bool = False
    ack: int = 0

    def pack(self):
        return self.header.pack(
                   self.syn, 
                   self.fin,
                   self.reset,
                   self.has_opt,
                   self.ack
               ) + self.payload.encode('utf-8')

    @classmethod
    def unpack(cls, data: bytes):
        payload = data[cls.header.size]
        syn, fin, reset, has_opt, ack = cls.header.unpack_from(data)
        return Packet(
                   payload.decode('utf'),
                   syn,
                   fin,
                   reset,
                   has_opt,
                   ack)
0
ответ дан chepner 1 March 2019 в 20:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: