在基於.NET的網絡服務端的開發中,我們用到和聽到的最多的恐怕就是異步 Socket了。異步Socket的性能比同步高出很多,但是編寫代碼比較復雜。因此異 步Socket也是網絡上討論比較多的話題。
今天,我們就來討論一下如何 用異步Socket開發網絡應用。在此之前我們先討論兩個問題。
一、異步 Socket是如何工作的:
那異步Socket是如何工作的呢?我以接收一條消 息來說明這個問題。首先,程序向系統投遞一個接收數據的請求,並為其指定一 個數據緩沖區和回調函數,回調函數用來指示當數據到達後將如何處理,然後我 們的程序繼續執行下去,當有數據到達的時候,系統將數據讀入緩沖區,並執行 回調函數,處理這條消息。我們並不需要關心這條消息何時到達。
二、 什麼情況下我們用異步Socket:
有些人認為,異步Socket的性能比同步 Socket的性能高很多,應該在各種環境下都用異步Socket,其實不然。在某些環 境下面。異步反到比同步的性能低,那麼在哪些情況下會這樣呢?
1、 客戶端Socket。
2、服務端連接數比較少。
3、連接數很多,但 都是短連接。
在這些環境下,我們用同步Socket不但可以簡化代碼,而 且性能並不會比異步Socket低。但在服務端連接比較多而且是長連接的情況下, 我們就要使用異步Socket。
現在我們來看看如何用異步Socket編程。
首先,我們要建立一個Socket用來監聽:
Socket _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(_address, _port);
_listener.Bind(localEP);
_listener.Listen (100);
然後創建一個線程來處理客戶端連接請求:
Thread _acceptWorkThread = new Thread (AcceptWorkThread);
_acceptWorkThread.Start();
private void AcceptWorkThread()
{
while (_isListener)
{
UserInfo info = new UserInfo();//這個UserInfo是用來保存客戶信息的。
info.socket = socket;
Socket socket = _listener.Accept ();
//這裡進行其它處理。
socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, ReceiveCallBack, info);//這裡向 系統投遞一個接收信息的請求,並為其指定ReceiveCallBack做為回調函數
}
}
我們再來看看回調函數的定義:
private void ReceiveCallBack(IAsyncResult ar)
{
UserInfo info = (UserInfo)ar.AsyncState;
Socket handler = info.socket;
int readCount = 0;
try
{
readCount = handler.EndReceive(ar);//調用這個函數來結束本次接收並返回接收到的數據 長度。
}
catch (SocketException)//出現Socket異常就關閉連接
{
CloseSocket(info);//這個函數用來關閉客戶端連接
return;
}
catch
{
}
if (readCount > 0)
{
byte[] buffer = new byte[readCount];
Buffer.BlockCopy(info.Buffer, 0, buffer, 0, readCount);
Analyzer(info, buffer);//這個函數用來處理接收到的信息。
try
{
handler.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);//向系統投 遞下一個接收請求
}
catch (SocketException) //出現Socket異常 就關閉連接
{
CloseSocket(info);
}
catch
{
}
}
else //如果接收到0字節的數據說明客戶端關閉了Socket,那 我們也要關閉Socket
{
CloseSocket(info);
}
}
接下來我們看看如何發送數據給客戶端:
public void Send(Socket socket, byte message)
{
try
{
info.socket.BeginSend(message, 0, _byte.Length, SocketFlags.None, new AsyncCallback(SendCallBack), info);//這裡向系統投遞一個發送數據的 請求,並指定一個回調函數。
}
catch (SocketException ex)
{
CloseSocket(info);
}
catch
{
}
}
定義發送回調函數:
private void SendCallBack(IAsyncResult ar)
{
UserInfo info = (UserInfo) ar.AsyncState;
try
{
info.socket.EndSend(ar);//調用這個 函數來結束本次發送。
}
catch
{
}
}
好了,整個監聽、接收、發送的過程就完成了,很簡單吧。現在 需要說明的是,我在這裡接收客戶端連接的Accept是用的同步的,我個人認為在 這裡用同步的會比用異步好一些。因為這樣代碼簡單而且沒有性能上的損失。
今天我就寫到這裡了!下次我們再繼續。