使用 struct.pack 和 struct.unpack 的问题
Issue using struct.pack and 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):
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 对其进行编码并通过套接字发送,然后使用解包将数据放回元组中,以便我可以从中提取必要的位它。我的数据包没有一些需要的位,因为它是使用数据包的最小示例。一旦我执行了行
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
的数据return,那么你传递给struct.unpack
的参数必须是return来自 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()
一些注意事项:
- 您可以pre-create一个
Struct
object来打包和解包header
- 有效载荷更容易自行打包和解包,与 header 分开。
它可以附加到打包的 header 并使用切片从数据包中提取。
unpack
应该是采用 bytes
object 和 returns 的 class 方法
Packet
. 的实例
- 将其设为数据class 可以避免为
__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)
这是我的代码片段:
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 对其进行编码并通过套接字发送,然后使用解包将数据放回元组中,以便我可以从中提取必要的位它。我的数据包没有一些需要的位,因为它是使用数据包的最小示例。一旦我执行了行
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
的数据return,那么你传递给struct.unpack
的参数必须是return来自 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()
一些注意事项:
- 您可以pre-create一个
Struct
object来打包和解包header - 有效载荷更容易自行打包和解包,与 header 分开。 它可以附加到打包的 header 并使用切片从数据包中提取。
unpack
应该是采用bytes
object 和 returns 的 class 方法Packet
. 的实例
- 将其设为数据class 可以避免为
__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)