2015-02-07 90 views
1

下面的工作正常,當有數據返回。然而,在下面的stream.read()掛起時返回一個空的流是有效的。我如何重構它以迎合這兩種情況?.NET TcpClient空&非空返回流

 using(TcpClient client = new TcpClient(_server, _port)) 
     using(NetworkStream stream = client.GetStream()) 
     { 
      stream.Write(data, 0, data.Length); 

      byte[] myReadBuffer = new byte[1024]; 

      int numberOfBytesRead = 0; 

      var message = new List<Byte>(); 

      do{ 
       numberOfBytesRead = stream.Read(myReadBuffer, numberOfBytesRead, myReadBuffer.Length); 

       message.AddRange(myReadBuffer.Take(numberOfBytesRead)); 

      } 
      while(stream.DataAvailable);   

      return message.ToArray(); 
     } 

回答

1

如果我理解正確的代碼示例,你真正想要做的是讀取所有從插座(即TCP連接)字節,然後返回它們作爲byte[]。如果是這樣的話,那麼這將是更好的:

using(TcpClient client = new TcpClient(_server, _port)) 
    using(NetworkStream stream = client.GetStream()) 
    using(MemoryStream output = new MemoryStream()) 
    { 
     stream.CopyTo(output); 
     return output.ToArray(); 
    } 

作爲一般規則,我反對使用DataAvailable財產強烈建議。在這種情況下,它特別不適合,因爲它所做的只是檢查可以從流中讀取多少個字節,如果它不爲零,則返回true。一個空的流永遠不會有可用的字節,因此,即使流不是空的(即無法知道另一端何時完成向您發送數據),也不會檢測到流的結束。

如果我誤解了,你真的只想返回可立即使用的字節,那麼我不能提供沒有更多上下文的答案。 正確的實現這一點的方法是使用異步I/O,並使用一個理解流的整體結構(即數據邊界在哪裏)的層,但實現該層的細節在您的問題中不存在,所以不可能根據這些方面提供具體的建議。

+0

你的理解是正確的。不幸的是,這兩種情況下,代碼現在在.CopyTo處被阻塞。我認爲這可能是NetworkStream特有的。 – 2015-02-07 18:46:05

+0

@MylesMcDonnell:如果'CopyTo()'阻塞,那麼遠程端點就會行爲不端。即它應該在完成發送時對連接進行優雅的關閉。請注意,假定流程是「連接,發送所有數據,關閉連接」。如果您希望保持連接打開,以便稍後可以發送更多數據,則需要更改協議,以便有機制在同一個連接上對單個傳輸進行分隔(例如,以字節長度傳輸之前) – 2015-02-07 18:49:28

+0

關於異步的有趣點IO;響應流只是一個任意長度的byte [],不需要以任何方式解釋/解析。 – 2015-02-07 18:50:48

1

您永遠無法知道是否會有更多數據來臨或流是否已耗盡。遠程端必須表示信號流結束。

通過關閉或關閉插座,您將讀取0字節,這是您停止閱讀的信號。或者,讓遠程側發送數據信令流的結束。

您使用DataAvailable是一個錯誤(99%的這種用法是錯誤)。 DataAvailable是毒藥。它告訴你現在有多少數據已經準備好以非阻塞的方式被讀取。 1us後,答案可能會有所不同。

你需要把它扔掉。

+0

是的,我已經完成了,謝謝。這是我在這個級別進行網絡編程的第一次嘗試,所以我在本書中犯了一個錯誤。 – 2015-02-08 09:44:17