我有一个使用python 3.6
运行的基本多线程客户端服务器现在一旦建立连接,我想创建将通过tcp / ip发送的应用程序级别数据包。这些目的是进行三次握手以识别多个客户端,然后对其进行身份验证。该数据包还将用于将某些有效负载发送到服务器。
由于python没有任何数据类型,例如结构,所以我很难创建这些数据包。我不能使用元组因为它们是不可变的,我尝试使用记录类并使用c_type中的结构。
使用recordclass时数据未正确发送,因为我不知道每个数据包的确切大小,我将recv()参数保持为最大限制但是如果数据包的长度较短,则会将客户端移动到阻塞状态然后是最大限度。 在使用c_type结构时,我可以发送数据,但是它的格式为 \ xbct \ x00 \ x106 \ xe0 \ x02ff \ xc8B ,我无法将其转换回原始格式。< / p>
任何形式的帮助都将受到高度赞赏。
编辑: 到目前为止我已经这样做了。我附在我正在使用的代码片段下面,结构字段只是随意的,我将在以后更改它们。
服务器端:
...
...
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)
...
...
客户方:
unpacked= (b'(\xbcY', b'\x00\xa0\xa6\xc2', 100.19999694824219)
但问题仍然存在,即使我解压缩收到的数据包后,字符串数据仍以字节格式保存,而浮点数据则正确转换。这是我得到的print语句输出
{{1}}
我尝试了不同的编码/解码方案,但到目前为止还没有任何工作,我无法将其转换回来
答案 0 :(得分:0)
您的代码的主要问题是您实际上并未发送字符串。
您已经定义了一个包含两个c_wchar_p
成员的结构 - 或者用C语言指定了wchar_t *
个指针。你发送这些指针,但从不发送他们指向的数据。这不可行。
您不能只发送包含任何语言指针的C struct
。您必须以某种方式编写一些包含实际字符串而不是指针的更高级协议,然后将序列化和反序列化的代码写入struct
。使用struct.pack
等功能而不是ctypes.Structure
附近的功能更容易。甚至更容易在诸如netstrings之类的更高级别协议之上进行操作,如果您只使用基于文本的协议和一些人类可读的框架,甚至更容易,例如换行转义的JSON文本,并以换行符作为分界线。
如果你真的想要一个基于仅将固定大小的结构转储到网络的二进制协议,你的结构必须是固定大小和自包含的。例如,如果您的packet_type
总是最多4个字符,而sensor_name
最多30个字符,并且可以为较短的名称留出空间,则可以这样做:
class app_packet(Structure):
_fields_ = [('packet_type',c_wchar*4),
('sensor_name',c_wchar*30),
('value',c_float)]
现在字符直接嵌入到结构中,因此它可以正常工作。
除非它不会真正起作用,因为您的数据类型不是网络可移植的。 wchar_t
可以是2个字节或4个字节 - 不仅在不同平台之间,甚至在使用不同编译器或同一平台上的标志构建的二进制文件之间。 (另外,它们当然是native-endian。)如果你真的想要嵌入的2字节或4字节字符串,你必须明确它:使用c_uint16
或c_uint32
,编码s.encode('utf-16')
或s.encode('utf-32')
,然后memcpy
或cast
和切片复制。但是当然它们在你的代码中不是字符串,除非你把它们拉出来,然后再把它们解码,然后解码它们,这时你可能首先使用正确的协议。
此外,还不清楚为什么你首先想要将握手数据存储在这样的结构中。为什么不将它作为元组(或namedtuple
或普通类)传递给两个字符串和一个浮点数,并在它从网络进入/进入时序列化/反序列化。
你在评论中提到你需要它们是可变的,但这并不能解释它;你想要可变的握手数据就更没意义了。此外,您可以简单地使用不同的字符串创建一个新的元组,而不是像字符串一样的成员,您可以在适当的位置进行变异。