Python struct作为网络数据包(未知字节序列)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python struct作为网络数据包(未知字节序列)相关的知识,希望对你有一定的参考价值。
我正在研究Python中的服务器引擎,用于我在GameMaker Studio 2中制作的游戏。我目前在制作和发送数据包方面存在一些问题。
我已成功设法建立连接并发送第一个数据包,但是如果打包结构中的第一个字节等于某个值,我找不到按顺序发送数据的解决方案,然后将其他数据解压缩到给定的序列。
例:
types = 'hhh' #(message_id, x, y) example
message_id = 0
x = 200
y = 200
buffer = pack(types, 0,x, y)
在服务器端:
data = conn.recv(BUFFER_SIZE)
mid = unpack('h', data)[0]
if not data: break
if mid == 0:
sequnce = 'hhh'
x = unpack(sequnce, data)[1]
y = unpack(sequnce, data)[2]
您的后续解码看起来会根据消息ID而有所不同?
如果是这样,您可能希望使用unpack_from
,它允许您仅从数据中提取第一个成员(现在写入,您的初始unpack
调用将生成异常,因为您正在处理的缓冲区大小不正确)。然后,您可以根据消息ID获得改变解包格式字符串的代码。该代码看起来像这样:
from struct import pack, unpack, unpack_from
while True:
data = conn.recv(BUFFER_SIZE)
# End of file, bail out of loop
if not data: break
mid = unpack_from('!h', data)[0]
if mid == 0:
# Message ID 0
types = '!hhh'
_, x, y = unpack(types, data)
# Process message type 0
...
elif mid == 1:
types = '!hIIq'
_, v, w, z = unpack(types, data)
# Process message type 1
...
elif mid == 2:
...
请注意,我们在每种情况下都会再次打包消息ID以及特定于ID的参数。如果你喜欢使用unpack_from
的可选偏移参数,你可以避免这种情况:
x, y = unpack_from('!hh', data, offset=2)
另一个解释说明:如果要在两台不同的机器之间发送消息,则应考虑“字节序”(字节顺序)。并非所有机器都像x86一样是“小端”。因此,通常以某个定义的字节顺序发送整数和其他结构化数字 - 传统上一直是“网络字节顺序”(这是大端),但只要你是一致的,它们都是可以的。您可以通过在每个格式字符串前加上'!'来轻松完成此操作。或者如上所示'<'(你需要对两边的每个格式字符串都这样做)。
最后,上面的代码可能适用于简单的“玩具”应用程序,但随着您的程序范围和复杂性的增加,您应该意识到,不能保证您的单个recv
调用实际上接收所有已发送的字节而不是其他字节(例如来自随后发送的缓冲区的字节)。换句话说,通常需要添加一个缓冲层,或者确保您已经收到并正在运行您想要的字节数。
你能解压整个数据到列表,然后在循环中检查它的元素吗?打包3次是什么原因?我想,你可以解压缩一次,然后使用该列表 - 首先检查它的长度,如果不是空的 - >检查第一个元素 - >如果等于特殊的那个,继续列表解析。你有这样的尝试吗?
以上是关于Python struct作为网络数据包(未知字节序列)的主要内容,如果未能解决你的问题,请参考以下文章
Python数据结构与算法(10)---二进制数据结构Struct