非同步Socket寫聊天程式

倉木澤發表於2006-05-09
Socket網路應用程式如同一般檔案I/O一樣在資料存取未完成的時候,整個應用程式會停滯,直到網路操作完全成功為止。若是遇上不佳的網路環境,這種情形將會嚴重影響整個網路程式的運作。對於網路延遲,.NET提供了自己的一組解決方法,非同步操作。

Socket類提供的方法成員中包含一組專門用來進行非同步操作的Socket方法。這些方法以成對出現:BeginConnect EndConnect 提供非同步聯機功能、BeginAccept EndAccept   提供非同步接受請求、 BeginReceive EndReceive  非同步接收資料、BeginSendEndSend       非同步傳送資料。

其實這些方法和同步相當類似,最大的差異在於AsyncCallback類派生物件,上述的非同步方法接受一個AsyncCallback物件,封裝回撥方法,並在Socket網路操作完成之後,返回IAsyncResult介面物件。此物件被當作引數。傳入回撥的方法,回撥的方法呼叫結束相關非同步方法,並且傳入IAsyncResult,取得相關的非同步操作資訊。

    public interface IAsyncResult

    public delegate void AsyncCallback (IAsyncResult ar)

ar 為非同步操作的結果,獲取非同步操作的返回值。

 

服務端程式碼示例

private static ManualResetEvent allDone = new ManualResetEvent(false); //執行緒訊號

    public static void StartListening(Socket listener, IPEndPoint localEndPoint)

    {

        listener.Bind(localEndPoint);

        listener.Listen(100);

        while (true)

        {

            allDone.Reset();  //將事件狀態設定為非終止狀態,導致執行緒阻止

            //開啟一個非同步Socket來監聽客戶端連線請求

            //並建立回撥,以便在有客戶請求連線後激發AcceptCallback()過程

            listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

            showMsg("正在等待一個新連線接入...");

            allDone.WaitOne();  //等待連線

        }

    }

    //請求回撥過程(當有一個新客戶端請求連線時發生)

    private static void AcceptCallback(IAsyncResult ar)

    {

        //從IAsyncResult介面中得到客戶端請求的Socket物件

        Socket listener = (Socket)ar.AsyncState;

        Socket handler = listener.EndAccept(ar);

        //StateObject:一個使用者定義物件,其中包含接收操作的相關資訊。當操作完成時,

        //此物件會被傳遞給EndReceive 委託。

        StateObject state = new StateObject();

        state.workSocket = handler;

        //建立一個接收資訊的回撥,以便在收到資訊時激發ReceiveCallback()過程

        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,

            new AsyncCallback(ReceiveCallback), state);

    }

    //接收資訊回撥過程(當接收到客戶端資訊時發生)

    private static void ReceiveCallback(IAsyncResult ar)

    {

        String content = String.Empty;

        StateObject state = (StateObject)ar.AsyncState;

        Socket handler = state.workSocket;

        //從客戶端的Socket中讀取資訊

        int bytesRead = handler.EndReceive(ar);

       //在此加入資訊處理並顯示接收到的資訊

        //建立一個新的接收資訊的回撥,以便在收到新資訊時繼續本過程

        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,

                new AsyncCallback(ReceiveCallback), state);

}

 

輔助物件

    public class StateObject

    {

        public Socket workSocket = null;

        public const int BufferSize = 256;

        public byte[] buffer = new byte[BufferSize];

        public string strMsg = string.Empty;

 }

 

客戶端程式

        private static ManualResetEvent connectDone = new ManualResetEvent(false);

        private static ManualResetEvent sendDone = new ManualResetEvent(false);

        private static ManualResetEvent receiveDone = new ManualResetEvent(false);

        private static String response = String.Empty;  //遠端裝置接收到的資訊

 

        public static void StartClient(Socket client, IPEndPoint remoteEP)

        {

            client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);

            connectDone.WaitOne();

        }

        private static void ConnectCallback(IAsyncResult ar)

        {

            Socket client = (Socket)ar.AsyncState;

            client.EndConnect(ar);

            System.Diagnostics.Debug.WriteLine("連線成功:" + client.RemoteEndPoint.ToString());

            connectDone.Set();

        }

        private static void Receive(Socket client)

        {

            //建立stateObject.

            StateObject state = new StateObject();

            state.workSocket = client;

            //開始從遠端裝置接收資訊

            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,

                new AsyncCallback(ReceiveCallback), state);

        }

        private static void ReceiveCallback(IAsyncResult ar)

        {

            StateObject state = (StateObject)ar.AsyncState;

            Socket client = state.workSocket;

            client = state.workSocket;

            //讀取資訊

            int bytesRead = client.EndReceive(ar);

            //資訊處理

        }

 

        public static void Send(Socket client, String data)

        {

            byte[] byteData = Encoding.UTF8.GetBytes(data);

            //向遠端裝置傳送資訊

            client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);

        }

 

        private static void SendCallback(IAsyncResult ar)

        {

            Socket client = (Socket)ar.AsyncState;

            //所有資訊已被髮送

            int bytesSent = client.EndSend(ar);

        }

上面的示例只說明瞭非同步聊天程式的原理,沒有對可能發生的異常進行處理和其它輔助方法。

http://blog.csdn.net/chendazhi/archive/2006/04/21/socket

相關文章