[C#] 於 Socket 連線中使用非同步處理作業

介紹於 Socket 連線中如何使用非同步處理作業方法,讓多個連線執行緒同時作業不必等待。

前言


  在上一篇 [ASP.NET] 使用 SSL Socket 建立 Client 與 Server 連接 文章中說明了如何建立一個 SSL Socket 連線方法,在上篇文章中的連線方式為一次處理一個連線工作的模式,但在某些情況下是需要同時處理多連線工作,所以在此文章中則說明該如何使用非同步處理方式來處理多連線工作的方法。

 

實作非同步處理連線


  首先先看到上篇文章中原本的連線接聽方法,如下。

public static void RunServer() 
{

    // 建立X509憑證
    ServerCertificate = new X509Certificate(Certificate, "ssl");
    // 監聽任何IP Address來的訊息
    listener = new TcpListener(System.Net.IPAddress.Any, 17170);
    // 開啟監聽
    listener.Start();

    while (IsRun)
    {
        TcpClient client = listener.AcceptTcpClient();
        ProcessClient(client);
    }
}

 

  要將以上的代碼修改成非同步處理作業需要使用到 BeginAcceptTcpClient 與 EndAcceptTcpClient 方法,此兩個方法是專門用於處理非同步作業的方法,如下。

public IAsyncResult BeginAcceptTcpClient (
	AsyncCallback callback,
	Object state
)
  • callback :作業完成時需要呼叫的委派方法。
  • state :自訂定義物件,在此為傳入 TcpListener 物件,作業完成後會傳遞給委派方法。

 

public TcpClient EndAcceptTcpClient (
	IAsyncResult asyncResult
)
  • asyncResult :呼叫 BeginAcceptTcpClient 方法時回傳,在此回傳 TcpClient 物件。

 

  瞭解要使用何種方法後,調整 RunServer 方法代碼如下。

private static ManualResetEvent tcpClientConnected = new ManualResetEvent(false);

public static void RunServer() 
{

    // 建立X509憑證
    ServerCertificate = new X509Certificate(Certificate, "ssl");
    // 監聽任何IP Address來的訊息
    listener = new TcpListener(System.Net.IPAddress.Any, 17170);
    // 開啟監聽
    listener.Start();

    while (IsRun)
    {
        // 設定成未收到信號
        tcpClientConnected.Reset();
        // 接收非同步連接
        listener.BeginAcceptTcpClient(new AsyncCallback(TcpListenerCallback), listener);
        // 等待連接
        tcpClientConnected.WaitOne();
    }
}

 

  看到以上調整後代碼,首先需要宣告 ManualResetEvent 用來控制個連線執行緒的狀態,在 While 迴圈中首先呼叫 Reset 設定連線為未收到訊號狀態,再呼叫 BeginAcceptTcpClient 方法帶入 Callback 方法與 listener 物件,最後呼叫 WaitOne 讓連線執行緒等待到收到訊號為止。

 

  當連線收到訊號時,就會呼叫之前指定的 Callback 方法,傳入 TcpListenerCallback 方法的 ar 參數就是之前呼叫 BeginAcceptTcpClient 帶入的 listener 物件,所以接收後首先將此物件轉型回 TcpListener 物件,接著呼叫 EndAcceptTcpClient 方法後將回傳 TcpClient 物件,最後再呼叫 Set 設定狀態為未收到訊號,讓其他連線能夠繼續接入處理,如下。

public static void TcpListenerCallback(IAsyncResult ar)
{
    TcpListener listener = (TcpListener)ar.AsyncState;
    TcpClient client = listener.EndAcceptTcpClient(ar);
    if (client.Connected)
    {
        // 設定為未收到信號,允許下一個連接
        tcpClientConnected.Set();
        // 進行處理
        ProcessClient(client);
    }
}

 

  以上就是在 Socket 連線中使用非同步處理方式的作法。

 

參考資料


ManualResetEvent 類別

TcpListener 類別

 

 


以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教
如有侵權內容也請您與我反應~謝謝您 :)