2016-02-23 151 views
1

簡短說明:Python TCP套接字數據有時會丟失部分。套接字溢出?

客戶端通過TCP套接字發送服務器數據。數據長度不同,並且是由分隔符分割的字符串「~~~ * ~~~」

大多數情況下,它工作正常。一段時間。幾分鐘之後,數據即將全面釋放。所以我開始跟蹤這個問題,數據在錯誤的地方結束了,因爲整個事情還沒有通過。

一切都進入服務器腳本,並由不同的分隔符分析- 新數據 - 然後放入隊列。這是代碼:

是的我知道緩衝區的大小是巨大的。不,我不會一次性發送那種大小的數據,但我正在與它一起玩耍。

class service(SocketServer.BaseRequestHandler): 
    def handle(self): 
     data = 'dummy' 

     #print "Client connected with ", self.client_address 
     while len(data): 
      data = self.request.recv(163840000) 
      #print data 
      BigSocketParse = [] 
      BigSocketParse = data.split('*-New*Data-*') 

      print "Putting data in queue" 
      for eachmatch in BigSocketParse: 
       #print eachmatch 
       q.put(str(eachmatch)) 

      #print data 
      #self.request.send(data) 

     #print "Client exited" 
     self.request.close() 


class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 
    pass 

t = ThreadedTCPServer(('',500), service) 
t.serve_forever() 

然後我有一個線程上運行,而不是q.empty():其中由其他分隔符解析數據「~~~ * ~~~」

所以這個工程的一段時間。我要發送的數據類型的示例:

2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42 
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com 
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~~~-15 

但事情開始中斷。所以我採取了一些控制數據,並在一個循環中發送。會工作一段時間,然後結果開始在錯誤的地方清盤。並且這在我的隊列中出現:

2016-02-23 18:01:24.140000~~~*~~~Snowboarding~~~*~~~Blue Hills~~~*~~~Powder 42 
~~~*~~~Board Rental~~~*~~~15.0~~~*~~~1~~~*~~~http://bigshoes.com 
~~~*~~~No Wax~~~*~~~50.00~~~*~~~No Ramps~~~*~~~2016-02-23 19:45:00.000000~~~*~ 

刪去最後一個「~~ -15」。

因此,完全相同的數據工作,然後以後不會。這對我來說意味着某種溢出。

客戶端連接是這樣的:

class Connect(object): 

    def connect(self): 
     host = socket.gethostname() # Get local machine name 
     #host = "127.0.0.1" 
     port = 500    # Reserve a port for your service. 
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     #print('connecting to host') 
     sock.connect((host, port)) 
     return sock 

    def send(self, command): 
     sock = self.connect() 
     #recv_data = "" 
     #data = True 

     #print('sending: ' + command) 
     sock.sendall(command) 
     sock.close() 
     return 

它不會等待響應,因爲我不希望它掛在等待一個做。但是它關閉了套接字,並且(據我所知),我不需要刷新套接字緩衝區,也不需要在連接關閉時自行清除它。

真的很感謝任何幫助。這一點讓我有點空閒。

更新:

我我的本地機器和一個漂亮結實的服務器上運行這一點,我會推到相信這是一個硬件問題。服務器/客戶端既在本地運行,也使用套接字作爲他們進行通信的方式,所以我不認爲延遲會是原因。

我一直在閱讀與TCP通信的問題。我覺得我會很快超出我的深度,但我開始懷疑它是不是一個溢出,但只是一些擁擠的王。

如果客戶端的sendall不能確保發送所有內容,那麼可能需要在服務器端進行某種計時器/檢查,以確保沒有更多事情即將到來。

+0

套接字緩衝是有可能的解釋 - 我遇到了這個問題,有一個實用程序從C++程序接收數據。在我這邊,問題在於處理每封郵件花費的時間太長。爲了解決這個問題,我們必須修改我的客戶端,以便在子進程完全讀取並填充隊列的情況下使用多處理。這使我可以在緩衝區溢出之前清除緩衝區。執行解析/處理必須在與接收分開的過程中進行。 –

+0

感謝您抽出時間。似乎移動得更快,但完全相同的錯誤發生在完全相同的地方。將使用線程代碼示例更新問題。 – PoweredByCoffee

+0

@PoweredByCoffee嘿你有沒有想到這一點。我有完全相同的問題。我的TCP服務器接收數據(使用我的自定義分隔符)約15-20分鐘,然後突然無法找到任何分隔符。數據仍然在收到。無論如何,如果你有解決方案,我會很感激。謝謝。 – PhilBot

回答

3

的基本問題是您:

data = self.request.recv(163840000) 

保證獲得一次所有數據(不管你有多大使緩衝)。

爲了正常工作,您必須處理一次沒有獲取所有數據的情況(您需要跟蹤您的位置並追加到它)。請參閱相關的例子在Python docs on using a socket

現在我們就來插座的主要絆腳石 - send和recv在網絡緩衝區操作。他們不一定處理你交給他們的所有字節(或者他們期望的),因爲他們的主要焦點是處理網絡緩衝區。一般來說,它們在關聯的網絡緩衝區被填充(發送)或清空(recv)時返回。然後他們會告訴你他們處理了多少字節。您有責任再次打電話給他們,直到您的信息完全處理完畢。

2

如上所述,即使您有較大的緩衝區大小,您仍未收到完整的消息。你需要繼續接收,直到你得到零字節。您可以編寫自己的發電機,該發電機採用request對象並生成零件。漂亮的一面是,你就可以開始處理郵件,而一些仍在

def recvblocks(request): 
    buf = '' 
    while 1: 
     newdata = request.recv(10000) 
     if not newdata: 
      if buf: 
       yield buf 
      return 
     buf += newdata 
     parts = buf.split('*-New*Data-*') 
     buf = parts.pop() 
     for part in parts: 
      yield part 

來,但你需要在客戶端上的修復也。您需要關閉套接字之前接近真正關閉TCP連接

sock.sendall(command) 
    sock.shutdown(request.SHUT_RDWR) 
    sock.close()