2013-10-25 183 views
0

我有一個方法可以通過TcpClientNetworkStream讀取一些數據,並且它給了我一些錯誤。TcpClient的NetworkStream讀取不完整的數據,除非調用Thread.Sleep(1)

在調查過程中,我發現它實際上工作正常......但只有當我使用Visual Studio 2012的調試器使用斷點逐步完成代碼時。

這裏是我的代碼:

public static byte[] DownloadStream(string hostname, int port, 
    byte[] requestBytes, int bufferSize = 4096) 
{ 
    byte[] responseBytes = null; 

    var client = new System.Net.Sockets.TcpClient(hostname, port); 

    if (client.Connected) 
    { 
     using (var stream = client.GetStream()) 
     { 
      stream.Write(requestBytes, 0, requestBytes.Length); 
      stream.Flush(); 

      if (stream.CanRead) 
      { 
       var responseStream = new System.IO.MemoryStream(); 

       byte[] buffer = new byte[bufferSize]; 
       int bytesRead = 0; 

       do 
       { 
        bytesRead = stream.Read(buffer, 0, buffer.Length); 

        responseStream.Write(buffer, 0, bytesRead); 
       } 
       while (stream.DataAvailable); 

       responseBytes = responseStream.ToArray(); 
      } 
     } 
    } 

    client.Close(); 

    return responseBytes; 
} 

這是非常令人沮喪,因爲沒有真正的錯誤。它顯然只需要調試器在讀取NetworkStream時握住它的手。

有人知道爲什麼會發生這種情況嗎?我該如何解決它?


編輯:

由於某種原因使這種變化消除了問題:

   do 
       { 
        bytesRead = stream.Read(buffer, 0, buffer.Length); 

        responseStream.Write(buffer, 0, bytesRead); 

        System.Threading.Thread.Sleep(1); //added this line 
       } 
       while (stream.DataAvailable); 

對此有何見解?

+0

請說明預期結果和實際結果。 –

+0

它只是不讀取所有的字節。結果是不完整的,最終導致我的應用程序的另一部分出現XML解析錯誤。 – Kehlan

+0

不要在循環中調用'stream.Read',而是嘗試調用'stream.CopyTo(responseStream)'(.NET 4及更高版本)並查看是否解決了問題。 –

回答

3

NetworkStream.DataAvailable屬性是不是一個可靠的方法來檢測響應的結束;如果響應被分割爲多個TCP數據包,並且在檢查DataAvailable時還沒有傳送數據包,則該屬性將返回false,提前終止循環。

顯然,您的網絡連接速度很快,以致Thread.Sleep(1)爲每個連續的數據包提供足夠的時間到達。然而,在一個較慢的連接上,它可能不夠用。

爲了可靠的通信,客戶端和服務器需要商定一種方式來表示響應的結束。例如:

  • 服務器可以在實際響應之前將響應的長度作爲前綴發送。客戶端讀取長度,然後從流中讀取數據直到它接收到該字節數。
  • 服務器可以在實際響應之後發送特殊終結符作爲後綴。客戶端從流中讀取直到它遇到終止符。 (顯然,終結器不能出現在響應本身的任何地方)。
  • 服務器可以在發送整個響應後關閉連接。客戶端從流中讀取直到連接關閉。
+0

睡眠實際上只是浪費時間。 – EJP

相關問題