【发布时间】:2018-09-03 05:41:49
【问题描述】:
我有一个使用 python 3.6 运行的基本多线程客户端服务器
现在一旦建立连接,我想创建将通过 tcp/ip 发送的应用程序级数据包。这样做的目的是进行三次握手以识别多个客户端,然后对它们进行身份验证。该数据包还将用于向服务器发送某些有效负载。
由于 python 没有任何数据类型,例如结构,所以我很难创建这些数据包。我不能使用元组,因为它们是不可变的,我尝试使用 recordclass 并使用 c_type 中的结构。
使用记录类时数据发送不正确,因为我不知道每个数据包的确切大小,我将 recv() 参数保持在最大限制,但是如果数据包的长度较短,这会将客户端移动到阻塞状态然后是最大限制。 在使用 c_type 结构时,我可以发送数据,但它是以 \xbct\x00\x106\xe0\x02ff\xc8B 这样的格式接收的,我无法将其转换回原始形式。
我们将不胜感激任何形式的帮助。
编辑: 到目前为止,我已经做到了。我附在我正在使用的代码 sn-ps 下面,结构字段是任意的,我稍后会更改它们。
服务器端:
...
...
class app_packet(Structure):
_fields_ = [('packet_type',c_wchar_p),
('sensor_name',c_wchar_p),
('value',c_float)]
syn=app_packet('syn','temperature',100.2)
connectionSocket.sendall(syn)
...
...
客户端:
...
...
class app_packet(Structure):
_fields_ = [('packet_type',c_wchar_p),
('sensor_name',c_wchar_p),
('value',c_float)]
data=clientSocket.recv(1024)
syn=unpack('3s4sf',data)
a=str(syn)
print("unpacked="+a)
...
...
但问题仍然存在,即使在我解包收到的数据包后,字符串数据仍为字节格式,而浮点数据已正确转换。这就是我得到的 print 语句的输出
unpacked= (b'(\xbcY', b'\x00\xa0\xa6\xc2', 100.19999694824219)
我尝试了不同的编码/解码方案,但到目前为止没有任何效果,我无法将其转换回来
【问题讨论】:
-
Python 确实有这样的数据类型——你在
ctypes中找到了它们——但通常你想使用struct模块来反序列化一个更“正常”的值到字节流中,或构建(或下载)在此之上构建的更高级别的序列化库。如果您可以给我们minimal reproducible example,我可以为您展示如何为您的情况做这件事。 -
此外,数据作为字节流接收,因为这就是您发送的内容,就像它们在 C 中一样。如果您想使用
ctypes.Structure,您需要转换字节返回给它,就像你必须将结构转换为字节来发送它一样。 -
还有一件事:如果您确实想围绕 Structure 而不是
struct模块构建东西,那么至少在开发过程中通常很有帮助的一个快速技巧是用相同字节大小的 char 或 uint8 数组将结构包装在 Union 中的类装饰器。这使得两种表示之间的转换更具可读性——只需设置字节元素,然后从结构元素中读取属性,反之亦然。如果这听起来像你想要的东西,但你不知道如何写它,那么演示并不难。 -
最后一件事——你需要这些是可变的吗?对于握手数据,我无法想象在构造(在发送端)或从字节转换(在接收端)之后要更改什么。如果您不想使用更高级别的东西,
namedtuple和基于struct的用于在有线协议之间进行转换的方法似乎正是正确的方法。 -
@abarnert 首先感谢您的帮助。您能告诉我将字节转换回来的方法吗?有没有预定义的方法呢。我希望这些是可变的的原因是我实际上是在尝试创建一个包含我需要的所有字段的单个数据包,然后根据数据包类型我将设置相关字段,如果它们是不可变的,我不能做那。即使我确实为握手制作了另一个单独的数据包,我也需要在其中发送我的客户端 ID,这样最终会改变。