2013-01-10 60 views
0

我有一個客戶端服務器通信,我寫了下面的服務器來處理傳入的消息,但如果消息比緩衝區大,它會丟失。如果消息大於緩衝區大小,我如何收到整個包?有沒有可能,或者我不得不強制客戶端(在最大緩衝區大小的請求下發送消息)在緩衝區大小內發送消息?Python的TCP緩衝區溢出

msg ='' 
while(True):     
    msg += server.recv(20480)          
    aSplit = msg.partition("</packet>") 
    #We received the full message 
    while(aSplit[ 1 ] == "</packet>"):       
      messagehandler( aSplit[ 0 ] + "</packet>")       
      msg = aSplit[ 2 ] 
      aSplit = msg.partition("</packet>") 

回答

3

當任何一種打包的消息格式的處理,你才真正有兩種選擇:

  1. 確保你的緩衝區足夠大,以應對整個消息。
  2. 編寫代碼以便它可以解析部分消息。

當我說「緩衝」,不過,我並不意味着recv()參數 - 你可以作出這樣的小,只要你喜歡,只是走在你的while循環多次,直到你有一個整個郵件。

因此,採取緩衝方式,你可以做這樣的事情:

msg = '' 
while True: 
    msg += server.recv(8192) 
    while True: 
     aSplit = msg.partition("</packet>") 
     if not aSplit[1]: 
      break 
     messagehandler(aSplit[0] + "</packet>") 
     msg = aSplit[2] 

這工作,因爲如果</packet>沒有找到,那麼partition()仍然返回一個3元組,其中第一項是整個字符串另外兩個是空的。因此,partition()一直爲分隔符返回一個非空字符串,然後發現一個數據包。一旦空了,就會有一個msg中的一部分數據包(或者它是空的),所以我們再回到從網絡讀取數據,直到我們再次獲取整個數據包。

這確實涉及緩衝msg字符串中的整個消息,但這很好,除非您希望這些消息變得非常大(多兆字節) - 例如,如果消息包含大文件,則可能會發生這種情況。在這種情況下,你需要更加聰明,並且做一些事情,比如將數據交換到磁盤,或者在收到數據時處理數據。

讓我知道,如果我不清楚任何。

編輯:我應該補充說,一般來說確保緩衝區(即msg)不會變得太大是個好主意 - 如果這樣做,那麼您需要關閉連接,因爲出現了問題。這會停止爲應用程序提供無盡的數據,直到內存在系統上耗盡,無論是意外還是惡意。此外,您需要確保字符串</packet>實際上不會發生在郵件內部 - 這會錯誤地將郵件分成一半。

+0

當我發送100KB的消息時,我仍然失去了消息的結尾 –

+0

這聽起來像是超出了操作系統的緩衝區來存儲數據。例如,如果您使用的是TCP連接,則可以發送的數據量是有限的 - 無論您的客戶在做什麼,它都可以一次讀取GB,這仍然會發生。你在發送端需要做的事情是注意'send()'的返回碼,它會告訴你發送了多少數據。你的應用程序必須繼續發送其餘的循環,直到它全部發送完畢。我建議你閱讀[Python sockets HOWTO](http://docs.python.org/2/howto/sockets.html)。 – Cartroo

+0

特別是,閱讀[使用套接字]一節(http://docs.python.org/2/howto/sockets.html#using-a-socket) - 我引用:*現在我們來到主要的絆腳石的套接字 - send和recv在網絡緩衝區上運行。他們不一定處理你交給他們的所有字節(或者期望他們),因爲他們的主要焦點是處理網絡緩衝區。* – Cartroo