2012-08-22 81 views
0

我在我的Android手機上創建一個程序,將相機的輸出發送到同一網絡上的服務器。這是我的Java代碼:如何保持TCP數據包不被丟棄?

camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() { 

    public void onPreviewFrame(byte[] data, Camera cam) { 

     try { 
      socket = new Socket("XXX.XXX.XXX.XXX", 3000); 
      out = socket.getOutputStream(); 
      out.write(data); 
      socket.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     camera.addCallbackBuffer(data); 
     } 

該服務器是服務器的NodeJS:

time = 0 

video_server.on 'connection', (socket) -> 
    buffer = [] 
    socket.on 'data', (data) -> 
      buffer.push data 
    socket.on 'end', -> 
      new_time = (new Date()).getTime() 
      fps = Math.round(1000/(new_time - time)*100)/100 
      console.log fps 
      time = new_time 

      stream = fs.createWriteStream 'image.jpg' 
      stream.on 'close', -> 
        console.log 'Image saved.', fps 
      stream.write data for data in buffer 
      stream.end() 

我的終端顯示約1.5 FPS(5 Mbps)的。我對網絡編程知之甚少,但我確實知道應該有足夠的帶寬。每張圖像在18 fps時爲640x480x1.5,約爲63 Mbps。本地網絡應該很容易處理,但我的Android調試器給了我很多「連接被拒絕」的消息。

任何幫助解決我的不良網絡做法將是偉大的。 (我會稍微進行圖像壓縮 - 但現在我需要優化這一步)。

+4

爲什麼你一直打開和關閉TCP連接? –

+0

學會玩弄? – Dave

+0

這裏沒有證據表明TCP數據包完全被丟棄,'連接被拒絕'與帶寬或丟包沒有任何關係。您的代碼在將任何文件寫入文件之前將接收到的圖像毫無意義地累積在內存中,這會浪費時間和空間。 – EJP

回答

5

您所設計的系統,使得它必須做很多次更多的工作比它應該這樣做。您需要建立連接並拆除每個傳輸的幀。這不僅會導致吞吐量下降,而且還會讓您失去資源。

通過合理的設計,傳輸幀所需的一切就是發送和接收幀數據。根據您的設計,對於每個幀,必須建立TCP連接(3個步驟),必須發送和接收幀數據,並且TCP連接必須被拆除。更糟的是,接收器無法知道它已收到所有的幀數據,直到發生連接關閉。所以這不能隱藏在後臺。

設計一個合理的協議,問題就會消失。

+0

好吧,如果我通過一個TCP連接有穩定的圖像數據流,那麼就吞吐量而言,我能做到最好嗎?還是有某種網絡分析(MTU優化?),我應該執行?感謝您的好方法。 – Nick

+0

你需要一些標題,這樣讀者才能知道它有一個完整的框架。我建議將頭文件和幀數據組合成單個緩衝區,以便您可以通過一次調用將其發送到'write'。在服務器中,你需要循環調用read,直到你有一個完整的框架。你可以循環直到你讀完一個完整的頭文件,然後循環,直到你讀完整幀數據(小心不要過度讀取),然後繼續讀取處理該幀後的下一個頭文件。你必須在寫作中積極主動,否則你可能會導致糟糕的Nagling /推遲ack。接收器中沒有這樣的問題。 –

+1

+1,因爲@DavidSchwartz就在這裏。使用TCP連接/斷開進行消息成幀只是可以想象的最糟糕的協議,對於視頻等需求尤其是高延遲無線網絡的需求來說是完全可怕的。你現在需要一個合理的協議! –

1

這樣工作嗎?我沒有看到你綁定到服務器端口3000的位置。

在任何情況下,如果這是一個視頻流,您應該使用UDP而不是TCP。在UDP中,數據包可能會丟失,但對於視頻流,這可能不會引起注意。由於交換的消息數量多,UDP通信所需的開銷比TCP少得多。 TCP包含很多「確認」以確保每條數據到達目的地; UDP不關心,因此發送較少的數據包。根據我的經驗,基於UDP的代碼通常不比基於TCP的代碼複雜。

_ryan

+0

是的,它的工作原理。我忽略了與問題無關的部分代碼和修改的位。我會閱讀UDP並給它一個鏡頭。有什麼我應該知道的最大化吞吐量與UDP? (我知道我可能需要重新排序分組,並且處理在另一端下降的。) – Nick

+1

UDP利用被稱爲最大傳輸單元(MTU)這就通常〜1500個字節的標準以太網幀的大小。如果你可以壓縮視頻,使得幀這個尺寸範圍內,你可以在這裏你從一端扔包,趕上他們在其他,而無需丟棄的數據包或重新排序或任何其他不必要的複雜性方面有一個非常簡單的協議。使用UDP,單個讀取操作可以讀取整個以太網幀的大小MTU,從而導致更小,更簡單的代碼和更好的性能。 – ryan0