2014-02-21 119 views
0

我經常編寫簡單的python TCP服務器,它在解析長度前綴的數據包之後響應請求。假設套接字已經設置,這通常是這樣的很多:解析來自TCP流的數據包

def tcp_server_loop(): 
    msg = '' 
    msg_len = 0 
    while True: 
     msg += sock.recv(4096) 
     if len(msg) >= 4 and msg_len == 0: 
      msg_len, = struct.unpack_from("!I", msg) 
     if len(msg) >= msg_len: 
      protocol.parse_packet(msg[:msg_len]) 
      msg = msg[msg_len:] 
      msg_len = 0 

這工作,並擔任我很多次,但我一直在字符串中msg += sock.recv(4096)追加irk'ed。對於小數據包來說,這並不算太壞,因爲爲這些小字符串分配新存儲的開銷並不差。但是對於大數據包(MB),Python的字符串實現在後臺進行大量複製。

在C語言或其他類似的語言中,環形緩衝區是一種明顯的數據結構,其大小與您期望的最大數據包一致。但是,我還沒有找到類似的Python實現。我想知道如果有人能改善我的代碼。你如何實現這些類型的服務器?

回答

1

首先提出一個快速建議:爲清晰起見,您可能希望將packet_size重命名爲msg_len。你試圖從TCP流解析出來的是應用層協議消息,而不是TCP段(又名TCP數據包)。

但是要解決您的問題:更有效的方法是,當您收到您的消息標題時,分配第二個長度爲msg_len的固定大小的bytearray緩衝區。用它來存儲隨後讀入的數據。

+0

爲變量名取點,更新原始代碼以使其更清晰。 – user3339161

+0

我不確定我瞭解如何創建一個bytearray提高效率。這不需要'msg'和字節數組之間的拷貝嗎?當前的實現只將一個片段傳遞給協議解析器,我相信這不需要拷貝。 – user3339161

+0

是的,但只要你'sock.recv()'的字節數不是很大,我想這個熱點就是追加到'msg'時的內存重新分配,而不是副本。如果你把'msg'寫入'bytearray',你可能會贏得一些額外的東西,不需要解釋器來進行類型轉換。 – cklin