简体   繁体   English

在Python中创建应用程序级别的数据包

[英]Creating application level packets in Python

I have a basic multi-threaded client server running using python 3.6 我有一个使用python 3.6运行的基本多线程客户端服务器

Now once a connection is established I want to create application level packets which will be sent over tcp/ip. 现在,一旦建立连接,我想创建将通过tcp / ip发送的应用程序级别数据包。 The purpose of these will be make a three-way handshake to identify multiple clients then authenticate them. 这些操作的目的是进行三次握手,以识别多个客户端,然后对其进行身份验证。 the packet will also be used to send certain payloads to the server. 该数据包还将用于向服务器发送某些有效负载。

Since python does not have any data type such as structures so i am having a hard time creating these packets.I cant use tuples because they are immutable, I have tried using recordclass and using Structures from c_type. 由于python没有任何数据类型(例如结构),因此我很难创建这些数据包。由于元组是不可变的,因此我无法使用元组,因此我尝试使用recordclass和c_type中的Structures。

Data is not sent properly while using recordclass, because i dont know the exact size each packet will be, i kept the recv() argument to a maximum limit but this moves the client to a blocking state if the packet's length is shorter then the maxium limit. 使用recordclass时无法正确发送数据,因为我不知道每个数据包的确切大小,因此我将recv()参数保持为最大限制,但是如果数据包的长度小于最大值,则这会将客户端移至阻塞状态限制。 And in using c_type structures i can send the data but it is received in a format like this \\xbct\\x00\\x106\\xe0\\x02ff\\xc8B and I cant convert it back to the original form. 在使用c_type结构时,我可以发送数据,但是会以\\ xbct \\ x00 \\ x106 \\ xe0 \\ x02ff \\ xc8B这样的格式接收数据,因此我无法将其转换回原始格式。

Any sort of help will be highly appreciated. 任何帮助将不胜感激。

EDIT: So far i have done this. 编辑:到目前为止,我已经做到了。 I am attaching below the code snippets i am using, the structure fields are just arbitrary i will change them later on. 我在我正在使用的代码段下方附加了结构字段,这些字段是任意的,稍后我将对其进行更改。

Server Side: 服务器端:

...
   ...
   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)
   ...
   ...

Client side: 客户端:

    ...
    ...
    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)
    ...
    ...

But the problem still remains, even after i unpack the received packet the string data remains in byte format, whereas the float data is converted properly. 但是问题仍然存在,即使在我解压缩收到的数据包后,字符串数据仍保持字节格式,而浮点数据已正确转换。 this is what i get for the output of the print statement 这是我得到的打印语句的输出

unpacked=  (b'(\xbcY', b'\x00\xa0\xa6\xc2', 100.19999694824219)

I have tried different encoding/decoding schemes but nothing is working so far, and i can not convert it back 我尝试了不同的编码/解码方案,但到目前为止没有任何工作,而且我无法将其转换回去

The main problem with your code is that you're not actually sending the strings. 代码的主要问题是您实际上没有发送字符串。

You've defined a structure that includes two c_wchar_p members—or, in C terms, wchar_t * pointers. 您已经定义了一个结构,其中包含两个c_wchar_p成员,或者用C术语, wchar_t *指针。 You send those pointers over, and but never send the data they're pointing to. 您将这些指针发送过来,但从不发送它们指向的数据。 That can't possibly work. 那可能行不通。

You can't just send C struct s containing pointers in any language. 您不能只发送包含任何语言的指针的C struct You have to write some higher-level protocol that includes the actual strings instead of the pointers in some way, and then write the code that serializes and deserializes to the struct . 您必须编写一些更高级别的协议,该协议以某种方式包括实际的字符串而不是指针,然后编写将序列化和反序列化到struct的代码。 Which is much easier to do with functions like struct.pack instead of around a ctypes.Structure . 使用诸如struct.pack之类的struct.pack而不是围绕ctypes.Structure进行处理要容易ctypes.Structure And even easier to do on top of a higher-level protocol like netstrings , and even easier if you just use a text-based protocol with some human-readable framing, like newline-escaped JSON texts with newlines as delimiters. 在诸如netstrings之类的更高级别协议之上进行操作甚至更容易,并且如果您仅使用基于人类可读框架的基于文本的协议(例如以换行符分隔的换行符JSON文本)则更加容易。


If you really want a binary protocol based on just dumping fixed-sized structures to the network, your structs have to be fixed-sized and self-contained. 如果您真的想基于仅将固定大小的结构转储到网络中的二进制协议,则您的结构必须是固定大小且独立的。 For example, if your packet_type were always at most 4 characters, and your sensor_name at most 30 characters, and it were acceptable to waste space for shorter names, you could do this: 例如,如果你的packet_type总是最多4个字符,而您的sensor_name最多30个字符,它是可以接受的,为较短的名称浪费空间,你可以这样做:

class app_packet(Structure):
    _fields_ = [('packet_type',c_wchar*4),
                ('sensor_name',c_wchar*30),
                ('value',c_float)]

Now the characters are embedded directly in the structure, so it will work. 现在,字符直接嵌入到结构中,因此可以正常工作。


Except that it won't really work, because your data types aren't network-portable. 除了它不能真正起作用,因为您的数据类型不是网络可移植的。 A wchar_t can be either 2 bytes or 4 bytes—not just between different platforms, but even between binaries built with different compilers or flags on the same platform. wchar_t可以是2个字节或4个字节-不仅在不同的平台之间,而且甚至在使用同一平台上的不同编译器或标志构建的二进制文件之间。 (Plus, they're of course native-endian.) If you really want embedded 2-byte or 4-byte strings, you have to be explicit about it: use c_uint16 or c_uint32 , encode with s.encode('utf-16') or s.encode('utf-32') , then either memcpy or cast and slice-copy. (此外,它们当然是native-endian。)如果您确实想要嵌入2字节或4字节的字符串,则必须对此加以明确:使用c_uint16c_uint32 ,使用s.encode('utf-16')进行编码) s.encode('utf-16')s.encode('utf-32') ,然后或者memcpycast和切片拷贝。 But then of course they're not strings within your code until you pull them out, cast them back, and decode them, at which point you might as well be using a proper protocol in the first place. 但是,当然,它们不是代码中的字符串,除非您将它们拉出,抛回它们并解码它们,这时您最好首先使用适当的协议。


Also, it's still not clear why you'd ever want handshake data to be stored in a structure like this in the first place. 同样,仍然不清楚为什么首先要将握手数据存储在这样的结构中。 Why not just pass it around as a tuple (or namedtuple or normal class) with two strings and a float, and serialize/deserialize right as it goes over/comes in from the network. 为什么不将它作为带有两个字符串和浮点数的元组(或namedtuple或普通类)传递,并在它从网络中通过/传入时立即对其进行序列化/反序列化。

You mentioned in a comment that you need them to be mutable, but that doesn't explain it; 您在评论中提到您需要使它们可变,但这并不能说明问题。 it makes even less sense that you'd want mutable handshake data. 您想要可变的握手数据就更没有意义了。 And besides, you can trivially just make a new tuple with different strings instead of having string-like members that you can mutate in place. 此外,您可以简单地使用不同的字符串创建一个新的元组,而不用拥有可以在适当位置进行突变的类似字符串的成员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM