2014-02-08 154 views
0

我必須使用一個只顯示同步套接字接口的套接字庫。我有幾個問題將此同步轉換爲異步。我從msdn示例開始(除了庫使用不同的通信算法外,庫接口類似於Microsoft套接字庫)。如何使同步套接字異步?

這是我目前的進展

private async void Start_Click(object sender, RoutedEventArgs e) 
    { 
     Log("Start server"); 
     var port = int.Parse(Port.Text); 
     var task = Task.Run(() => 
     { 
      // Establish the local endpoint for the socket. 
      // Dns.GetHostName returns the name of the 
      // host running the application. 
      Log("Hostname " + Dns.GetHostName()); 

      IPAddress[] ipv4Addresses = Array.FindAll(
       Dns.GetHostEntry(string.Empty).AddressList, 
       a => a.AddressFamily == AddressFamily.InterNetwork); 
      IPAddress[] ipv6Addresses = Array.FindAll(
       Dns.GetHostEntry(Dns.GetHostName()).AddressList, 
       a => a.AddressFamily == AddressFamily.InterNetworkV6); 

      foreach (var ip in ipv4Addresses) 
      { 
       Log("Ipv4 list " + ip); 
      } 
      foreach (var ip in ipv6Addresses) 
      { 
       Log("Ipv6 list " + ip); 
      } 

      var localEndPoint = new IPEndPoint(IPAddress.Any, port); 
      Log("Ip " + IPAddress.Any); 
      Log("Port " + port); 

      // Create a TCP/IP socket. 
      var listener = new Socket(AddressFamily.InterNetwork, 
       SocketType.Stream, ProtocolType.Tcp); 

      // Bind the socket to the local endpoint and 
      // listen for incoming connections. 
      try 
      { 
       listener.Bind(localEndPoint); 
       listener.Listen((int)SocketOptionName.MaxConnections); 
       Log("Max connection " + (int)SocketOptionName.MaxConnections); 

       // Start listening for connections. 
       bool isContinue = true; 
       while (isContinue) 
       { 
        Log("Waiting for a connection..."); 
        // Program is suspended while waiting for an incoming connection. 
        var handler = listener.Accept(); 


        // handle connection 
        // Data buffer for incoming data. 
        byte[] bytes = new Byte[1024]; 

        string data; 

        Log("Connection accepted"); 

        Log("Local endpoint " + handler.LocalEndPoint); 
        Log("Remote endpoint " + handler.RemoteEndPoint); 

        data = null; 

        // An incoming connection needs to be processed. 
        while (true) 
        { 
         bytes = new byte[1024]; 
         int bytesRec = handler.Receive(bytes); 
         data += Encoding.ASCII.GetString(bytes, 0, bytesRec); 
         if (data.IndexOf("<EOF>") > -1) 
         { 
          break; 
         } 
        } 

        // Show the data on the console. 
        Log("Text received " + data); 

        // Echo the data back to the client. 
        byte[] msg = Encoding.ASCII.GetBytes(data); 

        handler.Send(msg); 
        Log("Message sent"); 

        handler.Shutdown(SocketShutdown.Both); 
        Log("Shutdown"); 
        handler.Close(); 
        Log("Close"); 

        isContinue = true; 
       } 

      } 
      catch (Exception ex) 
      { 
       Log(ex.ToString()); 
      } 
     }); 
     await task; 
    } 
  1. 發生了什麼事時,我有2個或多個併發客戶端?
  2. 當第一個連接忙於通信時,第二個連接發生了什麼?
  3. 偵聽器是否立即偵聽listener.Accept()?
  4. 假設我有4個邏輯核心,當我在不同端口號的4個線程上偵聽時發生了什麼。這個監聽器中的每一個都阻塞了listener.Accept中的線程。我的用戶界面和電腦會發生什麼?它會掛起(所有核心都被使用和阻止)?
  5. 我有什麼可以參考的模式嗎?

我想使用任務,異步,等待,但我似乎無法構建在我的腦海。

我想通過添加套接字來改進此庫。

謝謝。

+1

[等待套接字操作](http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx) – Noseratio

+1

感謝您的鏈接。 –

+0

那麼這個第三方庫是否暴露了API的Begin/End風格? – Noseratio

回答

3

如果庫僅公開一個同步實現,表示它正在執行阻塞I/O。既然你不能改變它,因爲它是庫實現的一部分,你將不得不使用ThreadPool線程來委託工作。我已經寫了幾篇博客文章,其中提供了上下文(1,2)。

異步處理此工作只會在您想專門避免阻止特定線程(例如UI線程)時發生意義上的情況。在這種情況下,你可以簡單地perfom調用套接字庫是這樣的:

var task = Task.Run(() => 
    { 
    // run socket code 
    }); 

var result = await task; 
// rest of your code 

的調用Task.Run隊列工作線程池,等待避免,而工作是在一個單獨的線程進行阻塞UI線程。

+1

使用線程池進行自然異步操作是一個壞主意,如果可以避免的話:http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx – Noseratio

+1

@Noseratio我完全同意。這就是爲什麼我澄清,應該這樣做,因爲庫是阻塞的,只有當一個特定的線程不能被阻止。這對你有意義嗎? –

+1

它確實有道理。我沒有意識到有一個第三方庫參與,因爲OP只在他的代碼中使用標準套接字。我現在對你的答案進行了表決。 – Noseratio