.NET Socket開發之非同步Socket
在基於.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); 然後建立一個線程來處理用戶端串連請求:
我們再來看看回呼函數的定義:
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是用的同步的,我個人認為在這裡用同步的會比用非同步好一些。因為這樣代碼簡單而且沒有效能上的損失。