簡體   English   中英

在Python中創建應用程序級別的數據包

[英]Creating application level packets in Python

我有一個使用python 3.6運行的基本多線程客戶端服務器

現在,一旦建立連接,我想創建將通過tcp / ip發送的應用程序級別數據包。 這些操作的目的是進行三次握手,以識別多個客戶端,然后對其進行身份驗證。 該數據包還將用於向服務器發送某些有效負載。

由於python沒有任何數據類型(例如結構),因此我很難創建這些數據包。由於元組是不可變的,因此我無法使用元組,因此我嘗試使用recordclass和c_type中的Structures。

使用recordclass時無法正確發送數據,因為我不知道每個數據包的確切大小,因此我將recv()參數保持為最大限制,但是如果數據包的長度小於最大值,則這會將客戶端移至阻塞狀態限制。 在使用c_type結構時,我可以發送數據,但是會以\\ xbct \\ x00 \\ x106 \\ xe0 \\ x02ff \\ xc8B這樣的格式接收數據,因此我無法將其轉換回原始格式。

任何幫助將不勝感激。

編輯:到目前為止,我已經做到了。 我在我正在使用的代碼段下方附加了結構字段,這些字段是任意的,稍后我將對其進行更改。

服務器端:

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

但是問題仍然存在,即使在我解壓縮收到的數據包后,字符串數據仍保持字節格式,而浮點數據已正確轉換。 這是我得到的打印語句的輸出

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

我嘗試了不同的編碼/解碼方案,但到目前為止沒有任何工作,而且我無法將其轉換回去

代碼的主要問題是您實際上沒有發送字符串。

您已經定義了一個結構,其中包含兩個c_wchar_p成員,或者用C術語, wchar_t *指針。 您將這些指針發送過來,但從不發送它們指向的數據。 那可能行不通。

您不能只發送包含任何語言的指針的C struct 您必須編寫一些更高級別的協議,該協議以某種方式包括實際的字符串而不是指針,然后編寫將序列化和反序列化到struct的代碼。 使用諸如struct.pack之類的struct.pack而不是圍繞ctypes.Structure進行處理要容易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_uint16c_uint32 ,使用s.encode('utf-16')進行編碼) s.encode('utf-16')s.encode('utf-32') ,然后或者memcpycast和切片拷貝。 但是,當然,它們不是代碼中的字符串,除非您將它們拉出,拋回它們並解碼它們,這時您最好首先使用適當的協議。


同樣,仍然不清楚為什么首先要將握手數據存儲在這樣的結構中。 為什么不將它作為帶有兩個字符串和浮點數的元組(或namedtuple或普通類)傳遞,並在它從網絡中通過/傳入時立即對其進行序列化/反序列化。

您在評論中提到您需要使它們可變,但這並不能說明問題。 您想要可變的握手數據就更沒有意義了。 此外,您可以簡單地使用不同的字符串創建一個新的元組,而不用擁有可以在適當位置進行突變的類似字符串的成員。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM