我有一些结构,带有动态条目数。我从UDP接收字节数组,并按以下方式解析此消息:
class MsgStruct(Structure):
_pack_ = 1
def __init__(self, data=None):
if data:
self.unpack(data)
def unpack(self, raw):
fit = sizeof(self)
memmove(addressof(self), raw[:fit], fit)
def pack(self):
return bytearray(self)[:]
def size(self):
return sizeof(self)
class MessageEntry(MsgStruct):
_fields_ = [
('type', c_byte),
('flag', c_byte),
('count', c_int)]
class Message(MsgStruct):
_fields_ = [
('id', c_int),
('entry_count', c_int)]
entries = []
def __init__(self, data=None):
MsgStruct.__init__(self, data=data)
if data:
self.parseEntries(data[self.entry_count:])
def parseEntries(self, data):
offset = 0
size = sizeof(MessageEntry())
for count in range(self.entry_count):
entry = MessageEntry(data[offset:offset+size])
self.entries.append(entry)
offset += size
但是我认为有一种更好的方法可以使用ctypes.Array或POINTER解析消息并尝试执行以下操作:
class Message(MsgStruct):
_fields_ = [
('id', c_int),
('entry_count', c_int),
('entries', POINTER(MessageEntry))]
def __init__(self, data=None):
MsgStruct.__init__(self, data=data)
if data:
self.parseEntries(data[self.entry_count:])
def parseEntries(self, data):
offset = 0
size = sizeof(MessageEntry())
elems = (MessageEntry * self.entry_count)()
self.entries = cast(elems, POINTER(MessageEntry))
for count in range(self.entry_count):
self.entries[count] = MessageEntry(data[offset:offset+size])
offset += size
但是当我尝试打印条目时,我陷入了一个无尽的循环
msg = Message(x)
for i in msg.entries:
print(i)
我在做什么错? 有没有其他方法可以解析带有动态条目的消息?
答案 0 :(得分:1)
我想从一个注释开始,我看不到 entry_count 属性在哪里初始化。
在指针上进行迭代,就好像它是一个 size 数组在概念上是错误的(如[Python 3]: ctypes - A foreign function library for Python中所指出)。在 C 中,可能会超出数组范围,但是 ctypes 禁止这样做。
这是一个更简单的示例,它使用ctypes.c_char
作为基本类型( MessageEntry 对应对象)。
code.py :
#!/usr/bin/env python3
import sys
import ctypes
def main():
CharArr5 = ctypes.c_char * 5
b5 = b"12345"
ca5 = CharArr5(*b5)
print("Print array ...")
for c in ca5:
print(c)
cp = ctypes.cast(ca5, ctypes.POINTER(ctypes.c_char))
max_values = 10
print("\nPrint pointer (max {:d} values) ...".format(max_values))
for idx, c in enumerate(cp):
print(c)
if idx >= max_values:
print("Max value number reached.")
break
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
输出:
(py_064_03.06.08_test0) e:\Work\Dev\StackOverflow\q054178876>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32 Print array ... b'1' b'2' b'3' b'4' b'5' Print pointer (max 10 values) ... b'1' b'2' b'3' b'4' b'5' b'\x00' b'\x00' b'\x00' b'\x00' b'\x00' b'\x00' Max value number reached.
如所见,可以遍历指针,但是循环永远不会结束(当到达不可用/无效的内存地址时它将结束,程序将 segfault (访问冲突))。
假设已正确初始化 entry_count (,请确保对其进行初始化),使用它将循环保持在边界内(如下所示):>
for idx in range(msg.entry_count):
msg.entries[idx] # Do smth with it
# ...
for idx, entry in enumerate(msg.entries):
if idx >= msg.entry_count:
break
entry # Do smth with it
# ...
或者您可以使用上述方法之一为 Message 实现迭代器协议。