2016-10-03 41 views
1

我正在創建一個可以有多個客戶端的異步服務器。與聊天客戶端/服務器體系結構類似,所有客戶端都根據任何客戶端的請求更新每個服務器狀態更改。我發現了很多示例可供遵循,並編寫了一個簡單的測試應用程序。我剛剛寫過客戶端請求的處理,但遇到了我通常不會遇到的情況。下面是我寫的樣本服務器:應該始終等待任務嗎?

class Server 
{ 
    int _port; 
    TcpListener _listener; 
    IList<TcpClient> _clients = new List<TcpClient>(); 

    public Server(int port) 
    { 
     _port = port; 
     _listener = new TcpListener(IPAddress.Any, _port); 
    } 

    public async Task StartListening() 
    { 
     _listener.Start(); 
     Console.WriteLine("The server is listening on port {0}...", _port); 

     while (true) 
     { 
      try 
      { 
       var client = await _listener.AcceptTcpClientAsync(); 
       Console.WriteLine("We have a client!"); 
       _clients.Add(client); 
       Process(client); 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
     } 
    } 

    private async Task Process(TcpClient client) 
    { 
     try 
     { 
      var stream = client.GetStream(); 
      var reader = new StreamReader(stream); 
      var writer = new StreamWriter(stream) { AutoFlush = true }; 
      char[] buffer = new char[1024]; 
      while (true) 
      { 
       var request = await reader.ReadLineAsync(); 
       if (request != null) 
       { 
        Console.WriteLine(request); 
       } 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      client.Close(); 
     } 
    } 

} 

這裏的Program.cs:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var server = new Server(6029); 
     server.StartListening().Wait(); 
    } 
} 

我得到的進程調用一個警告,因爲任務不等待。我理解沒有等待調用的代碼的行爲,但我想知道是否應該以不同的方式進行編碼(ThreadPool等),即使這給了我想要的行爲。是否應該等待任務?

+1

'如果任務總是期待已久的'不...消防忘記任務也有一些用法.. –

回答

0

很難知道你真的在這裏問什麼。您已經詢問了暗示的具體問題「我想知道我是否應該以不同的方式編碼」以及廣泛的,主要是基於觀點的問題「應始終等待任務嗎?」

關於後者,唯一可以想象的正確答案是「不」。編程上幾乎沒有任何東西需要完成總是

也就是說,您發佈的代碼當然顯得有缺陷。首先,你有一個永遠不可能完成的async Task方法。那有什麼意義呢?你不妨宣佈它async void。該程序可以通過其他機制無限期地等待,比如無限長的睡眠時間或阻止方法等。

更好的是,給程序一種適當關閉自己的方法。希望服務器停止監聽時關閉監聽套接字。存儲Process()返回的所有Task對象,然後在允許進程完成之前等待它們,以確保您的服務器正常關閉連接而不是強制重置它們。

您發佈的代碼本身並不具體,不足以提供任何具體的建議方式。它看起來像起始代碼,主要用於演示一些基本概念,而不是真正做任何事情。因此,在所有情況下,它都必須遵循不同的規則,而不是代碼才能正常工作。


在我看來,鑑於你的代碼示例中,我等候在某一時刻,你創建的任務。您不一定需要使用await Process(...)(事實上,您可能不想這樣做,因爲這會阻止您一次處理多個客戶端),但您應該保留參考並最終等待。

但是這是否意味着Task必須總是等待?不,這只是在你的例子中,你沒有表現出一個令人信服的理由。在大多數情況下,你應該。如果沒有別的,它會讓你有機會觀察可能發生的任何異常(說到這種情況,你不應該捕捉到Exception&hellip;只捕捉你期望的異常,並且你肯定知道如何處理這些異常)。但是在極少數情況下,如果沒有其他原因而不是純粹的實用性(或者說,試圖觀察任務的不切實際性),那麼在開始的任務開始時就不理會已經開始的任務是合理的。


補充閱讀:
How to safely call an async method in C# without await
warning this call is not awaited, execution of the current method continues
Where to stop using async /await keywords?