2016-01-08 171 views
2

請原諒我對任務和異步的認識不足。TcpClient;的NetworkStream; ReadAsync; C#

使用TcpClient類我建立與可用服務器的連接:

void async RunClientAsync() 
{ 
    TcpClient client = new TcpClient(); 
    try 
    { 
     await client.ConnectAsync(IPAddress.Parse("1.1.1.1"), 8889); 
     Task.Start(() => ReadClientAsync(client)); 
    } 
    catch (Exception ex) 
    { 
     HandleException(ex); 
    } 
} 

// ----- 

void async ReadClientAsync(TcpClient client) 
{ 
    byte[] bf = new byte[2048]; 
    try 
    { 
     while(true) 
     { 
      int br = await client.NetworkStream().ReadAsync(); 
      if (br > 0) 
      { 
       HandleInboundData(bf, br); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     HandleException(ex); 
    } 
} 

的輔助方法HandleException(異常前)和HandleInboundData(字節[]緩衝液,INT長度)將執行假定任務。

與服務器的連接將是永久和從服務器接收到的數據將是未知的長度和頻率的,其想法是拋出一個任務在那裏,接收和處理,只有當數據是可用的入站數據。

ReadClientAsync(TcpClient客戶端)明顯失敗,因爲如果沒有可用數據,ReadAsync將始終返回0字節。

我應該如何使用async/task編寫ReadClientAsync以防止繁忙循環情況?在這些情況之前,我已經使用了BeginRead/EndRead,它工作正常。這是否是這種特殊情況下的解決方案?

謝謝,

+0

謝謝你的評論。這是來自ReadAsync的MSDN條目:「表示異步讀取操作的任務。TResult參數的值包含讀入緩衝區的總字節數。如果當前可用的字節數小於請求的數字,結果值可能會小於請求的字節數,如果已到達流的末尾,結果值可能爲0(零)。「我理解了流的結束意味着流中沒有數據要讀取。 – Jam

+0

瞭解。謝謝Luaan。我相信我明白問題出在哪裏。 – Jam

回答

4

不,這不是TCP的工作原理。

NetworkStream被認爲是在另一方發起(可能的單向)關閉時處於「流結束」狀態。那時ReadAsync(或Read,就此而言)返回零 - 不在其他情況下。

MSDN文檔很容易被誤解 - 主要是因爲您正在查看錯誤的文檔。 NetworkStream不會覆蓋ReadAsync(沒有理由這樣做),所以您實際上正在查看通用Stream.ReadAsync的文檔。相反,NetworkStream.Read的說明文件說:

該方法將數據讀入緩衝區參數並返回成功讀取的字節數。如果沒有數據可用於讀取,則Read方法返回0. Read操作讀取儘可能多的數據,直到由size參數指定的字節數。如果遠程主機關閉連接,並且已收到所有可用數據,則Read方法立即完成並返回零字節。

請注意最後一句,它告訴你它實際上對於NetworkStream是什麼意思是「流結束」。這是TCP連接如何關閉的。

您對此的迴應通常應該是關閉另一端的連接--以外的輔助方法並清理套接字。在任何情況下,不要再次重複while (true) - 你只會得到一個無限循環,它可以100%地處理你的CPU。

如果您想要了解如何處理帶有await的C#異步套接字的幾個指針,請查看我的示例https://github.com/Luaancz/Networking/tree/master/Networking%20Part%202。請注意免責聲明 - 這絕不是生產準備就緒。但它確實解決了人們在實現TCP通信時犯的一些常見錯誤。

相關問題