Skip to main content
 首页 » 编程设计

python之使用 struct.pack 和 struct.unpack 的问题

2025年05月04日19softidea

这是我的代码片段:

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): 
        unpackedData = bytearray() 
        return struct.unpack('????i5s', unpackedData) 
 
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() 

我的目标是创建一个数据包,使用 struct.pack 对其进行编码并通过套接字发送,然后使用 unpack 将数据放回元组中,以便我可以从中提取必要的位。我的数据包没有一些需要的位,因为它是使用数据包的最小示例。一旦我执行了这条线

packedData = packet.pack() 
print(packedData) 

我收到这个作为我的输出:

b'\x01\x01\x01\x00\xf9\x00\x00\x00Hello' 

这似乎是我所期望的,但是当我运行以下行时出现问题:

 unpackedData = packet.unpack() 
 print(unpackedData) 

我收到以下错误:

unpack requires a bytes object of length 13 

如果我将解压数据更改为长度为 13 的字节数组,我将得到以下输出作为我的解压数据:

(False, False, False, False, 0, b'\x00\x00\x00\x00\x00') 

这显然是错误的,因为它没有保留我的值,而且看起来只是一个不同的数据包实例。

我是否错误地创建了数据包对象?或者我是否错误地打包和解包了我的数据?

请您参考如下方法:

如果您希望 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()