實(shí)現(xiàn)基于事件通知的.Net套接字
更新時(shí)間:2006年09月28日 00:00:00 作者:
以前學(xué)過(guò)MFC,我用過(guò)的它里面的包裝Winsock的兩個(gè)類(lèi)CSocket和CAsyncSocket,我一直覺(jué)得它哪個(gè)事件通知的功能比較不錯(cuò),特別是在連接的兩方收發(fā)數(shù)據(jù)沒(méi)有一定的規(guī)律的時(shí)候比較有用,雖然不用它的事件通知也可以實(shí)現(xiàn)功能,但是你需要循環(huán)檢測(cè)套接字的狀態(tài)或者阻塞等待,如果每次都要做這些瑣碎的工作豈不是很麻煩,于是我就想對(duì)這些功能作一次封裝。當(dāng)然在.net里面采用delegate和event是最好的選擇了。下面就是我實(shí)現(xiàn)的一些細(xì)節(jié):
先講一下思路:其實(shí)這個(gè)還是很簡(jiǎn)單了,估計(jì)高手們會(huì)不屑一顧了^_^。當(dāng)套接字開(kāi)始工作,比如開(kāi)始監(jiān)聽(tīng)、開(kāi)始連接的時(shí)候,啟動(dòng)一個(gè)線程不停的檢測(cè)套接字的狀態(tài),當(dāng)某一事件的狀態(tài)條件滿(mǎn)足時(shí)就觸發(fā)此事件,要知道具體檢測(cè)套接字狀態(tài)的方法,請(qǐng)往下看。
平常用套接字編成的時(shí)候可能需要用到的功能就是:連接成功或者失敗的通知、在監(jiān)聽(tīng)的套接字上有掛起的連接的通知、有數(shù)據(jù)可以接受的通知、套接字關(guān)閉的通知、還有套接字空閑可以發(fā)送數(shù)據(jù)的通知等,我也就使對(duì)上面幾個(gè)功能作了封裝,不過(guò)我覺(jué)得最后面一個(gè)功能用處不大???
我的Socket類(lèi)是從System.Net.Sockets.Socket繼承下來(lái)的,類(lèi)名TcpEventSocket,實(shí)現(xiàn)如下:
先申明事件的委托類(lèi)型,具體看代碼
public delegate void AcceptConnectionHandler();
public delegate void ConnectCompletedHandler(bool connected); //connected表明連接成功與否
public delegate void DataCanSendHandler();
public delegate void DataCanReceiveHandler(int buffersize); //當(dāng)前可以接受的數(shù)據(jù)量
public delegate void SocketClosedHandler();
這些類(lèi)型具體什么意思應(yīng)該能看出來(lái)吧,另外還要申明對(duì)應(yīng)的事件
public event AcceptConnectionHandler AcceptConnection;
public event ConnectCompletedHandler ConnectCompleted;
public event DataCanSendHandler DataCanSend;
public event DataCanReceiveHandler DataCanReceive;
public event SocketClosedHandler SocketClosed;
另外加了幾個(gè)虛方法,這幾個(gè)方法用來(lái)觸發(fā)事件
protected virtual void OnAcceptConnection();
protected virtual void OnConnectCompleted(bool connected)
protected virtual void OnDataCanSend()
protected virtual void OnDataCanReceive(int buffersize)
protected virtual void OnSocketClosed()
為了在適當(dāng)?shù)氖聶C(jī)啟動(dòng)檢測(cè)線程,我重寫(xiě)了幾個(gè)基類(lèi)的方法:
new public void Listen(int backlog)
{
base.Listen(backlog);
sockState = SocketState.Listenning;
if (!checkThread.IsAlive)
checkThread.Start();
}
new public void Connect(EndPoint remoteEP)
{
try
{
base.Connect(remoteEP);
this.Blocking = false; //設(shè)置非阻塞狀態(tài),以便事件通知的效率
if (!checkThread.IsAlive)
checkThread.Start();
}
catch(SocketException)
{
OnConnectCompleted(false);
}
}
這兩個(gè)方法實(shí)際編成中都應(yīng)該首先被調(diào)用的,所以有他們啟動(dòng)檢測(cè)線程比較合適,另外線程啟動(dòng)了必然也要中止,于是我重寫(xiě)了Close方法
new public void Close()
{
if(checkThread.IsAlive) //先中止線程再關(guān)閉連接
checkThread.Abort();
base.Close();
sockState = SocketState.Disconnected;
OnSocketClosed();
}
于是剩下的工作就是怎么檢測(cè)套接字了,Socket類(lèi)有個(gè)Select的靜態(tài)方法,它可以檢測(cè)很多套接字的狀態(tài),不過(guò)這里只需要檢測(cè)一個(gè),所以直接用Socket的Poll方法,Poll的具體用法可以看MSDN,我這里用代碼說(shuō)明我對(duì)套接字的檢測(cè)方法
while(true) //循環(huán)檢查
{
if (sockState == SocketState.Disconnected) //如果當(dāng)前沒(méi)有連接
{
if (Poll(500, SelectMode.SelectWrite))
OnConnectCompleted(true); //如果為可寫(xiě)狀態(tài),則表示連接成功
}
else if(sockState == SocketState.Listenning)
{
if (Poll(500, SelectMode.SelectRead)) //如果在監(jiān)聽(tīng)狀態(tài)發(fā)現(xiàn)套接字有數(shù)據(jù)可讀則表示已經(jīng)有人連接上來(lái)可以調(diào)用Accept接受連接
OnAcceptConnection();
}
else //這里sockState = SocketState.Connected
{
if (Poll(500, SelectMode.SelectWrite)) //如果有可寫(xiě)狀態(tài)則表示可以發(fā)送數(shù)據(jù)
OnDataCanSend();
if (Poll(500, SelectMode.SelectRead)) //如果有可讀狀態(tài)
{
if (Available > 0) //如果有數(shù)據(jù)可讀表示可以調(diào)用Receive接受數(shù)據(jù)
OnDataCanReceive(Available);
else
{
OnSocketClosed(); //沒(méi)數(shù)據(jù)可讀表示連接已經(jīng)關(guān)閉
break;
}
}
}
//如果沒(méi)有連接并且有錯(cuò)誤狀態(tài),則連接失敗
if (sockState == SocketState.Disconnected && Poll(500, SelectMode.SelectError))
OnConnectCompleted(false);
}
這里的OnXXX方法就是執(zhí)行事件通知的方法,并且派生類(lèi)中可以重載這些方法直接獲得事件通知而不需要掛界別的事件通知處理函數(shù)(類(lèi)似于MFC的OnAccept等虛函數(shù))。不過(guò)派生的函數(shù)集的調(diào)用基類(lèi)的相應(yīng)方法哦。很可惜沒(méi)有重寫(xiě)Socket.Accept方法,讓它返回一個(gè)TcpEventSocket,這樣應(yīng)該就比較完整了,只可惜我不知道怎么做^_^,如果誰(shuí)知道的話歡迎指教。
事件通知機(jī)制已經(jīng)基本完成,所缺乏的只是大量的測(cè)試(我做了幾下最簡(jiǎn)單的測(cè)試,慚愧!!^_^)
如果有問(wèn)題請(qǐng)聯(lián)系 yzx110@bit.edu.cn
先講一下思路:其實(shí)這個(gè)還是很簡(jiǎn)單了,估計(jì)高手們會(huì)不屑一顧了^_^。當(dāng)套接字開(kāi)始工作,比如開(kāi)始監(jiān)聽(tīng)、開(kāi)始連接的時(shí)候,啟動(dòng)一個(gè)線程不停的檢測(cè)套接字的狀態(tài),當(dāng)某一事件的狀態(tài)條件滿(mǎn)足時(shí)就觸發(fā)此事件,要知道具體檢測(cè)套接字狀態(tài)的方法,請(qǐng)往下看。
平常用套接字編成的時(shí)候可能需要用到的功能就是:連接成功或者失敗的通知、在監(jiān)聽(tīng)的套接字上有掛起的連接的通知、有數(shù)據(jù)可以接受的通知、套接字關(guān)閉的通知、還有套接字空閑可以發(fā)送數(shù)據(jù)的通知等,我也就使對(duì)上面幾個(gè)功能作了封裝,不過(guò)我覺(jué)得最后面一個(gè)功能用處不大???
我的Socket類(lèi)是從System.Net.Sockets.Socket繼承下來(lái)的,類(lèi)名TcpEventSocket,實(shí)現(xiàn)如下:
先申明事件的委托類(lèi)型,具體看代碼
public delegate void AcceptConnectionHandler();
public delegate void ConnectCompletedHandler(bool connected); //connected表明連接成功與否
public delegate void DataCanSendHandler();
public delegate void DataCanReceiveHandler(int buffersize); //當(dāng)前可以接受的數(shù)據(jù)量
public delegate void SocketClosedHandler();
這些類(lèi)型具體什么意思應(yīng)該能看出來(lái)吧,另外還要申明對(duì)應(yīng)的事件
public event AcceptConnectionHandler AcceptConnection;
public event ConnectCompletedHandler ConnectCompleted;
public event DataCanSendHandler DataCanSend;
public event DataCanReceiveHandler DataCanReceive;
public event SocketClosedHandler SocketClosed;
另外加了幾個(gè)虛方法,這幾個(gè)方法用來(lái)觸發(fā)事件
protected virtual void OnAcceptConnection();
protected virtual void OnConnectCompleted(bool connected)
protected virtual void OnDataCanSend()
protected virtual void OnDataCanReceive(int buffersize)
protected virtual void OnSocketClosed()
為了在適當(dāng)?shù)氖聶C(jī)啟動(dòng)檢測(cè)線程,我重寫(xiě)了幾個(gè)基類(lèi)的方法:
new public void Listen(int backlog)
{
base.Listen(backlog);
sockState = SocketState.Listenning;
if (!checkThread.IsAlive)
checkThread.Start();
}
new public void Connect(EndPoint remoteEP)
{
try
{
base.Connect(remoteEP);
this.Blocking = false; //設(shè)置非阻塞狀態(tài),以便事件通知的效率
if (!checkThread.IsAlive)
checkThread.Start();
}
catch(SocketException)
{
OnConnectCompleted(false);
}
}
這兩個(gè)方法實(shí)際編成中都應(yīng)該首先被調(diào)用的,所以有他們啟動(dòng)檢測(cè)線程比較合適,另外線程啟動(dòng)了必然也要中止,于是我重寫(xiě)了Close方法
new public void Close()
{
if(checkThread.IsAlive) //先中止線程再關(guān)閉連接
checkThread.Abort();
base.Close();
sockState = SocketState.Disconnected;
OnSocketClosed();
}
于是剩下的工作就是怎么檢測(cè)套接字了,Socket類(lèi)有個(gè)Select的靜態(tài)方法,它可以檢測(cè)很多套接字的狀態(tài),不過(guò)這里只需要檢測(cè)一個(gè),所以直接用Socket的Poll方法,Poll的具體用法可以看MSDN,我這里用代碼說(shuō)明我對(duì)套接字的檢測(cè)方法
while(true) //循環(huán)檢查
{
if (sockState == SocketState.Disconnected) //如果當(dāng)前沒(méi)有連接
{
if (Poll(500, SelectMode.SelectWrite))
OnConnectCompleted(true); //如果為可寫(xiě)狀態(tài),則表示連接成功
}
else if(sockState == SocketState.Listenning)
{
if (Poll(500, SelectMode.SelectRead)) //如果在監(jiān)聽(tīng)狀態(tài)發(fā)現(xiàn)套接字有數(shù)據(jù)可讀則表示已經(jīng)有人連接上來(lái)可以調(diào)用Accept接受連接
OnAcceptConnection();
}
else //這里sockState = SocketState.Connected
{
if (Poll(500, SelectMode.SelectWrite)) //如果有可寫(xiě)狀態(tài)則表示可以發(fā)送數(shù)據(jù)
OnDataCanSend();
if (Poll(500, SelectMode.SelectRead)) //如果有可讀狀態(tài)
{
if (Available > 0) //如果有數(shù)據(jù)可讀表示可以調(diào)用Receive接受數(shù)據(jù)
OnDataCanReceive(Available);
else
{
OnSocketClosed(); //沒(méi)數(shù)據(jù)可讀表示連接已經(jīng)關(guān)閉
break;
}
}
}
//如果沒(méi)有連接并且有錯(cuò)誤狀態(tài),則連接失敗
if (sockState == SocketState.Disconnected && Poll(500, SelectMode.SelectError))
OnConnectCompleted(false);
}
這里的OnXXX方法就是執(zhí)行事件通知的方法,并且派生類(lèi)中可以重載這些方法直接獲得事件通知而不需要掛界別的事件通知處理函數(shù)(類(lèi)似于MFC的OnAccept等虛函數(shù))。不過(guò)派生的函數(shù)集的調(diào)用基類(lèi)的相應(yīng)方法哦。很可惜沒(méi)有重寫(xiě)Socket.Accept方法,讓它返回一個(gè)TcpEventSocket,這樣應(yīng)該就比較完整了,只可惜我不知道怎么做^_^,如果誰(shuí)知道的話歡迎指教。
事件通知機(jī)制已經(jīng)基本完成,所缺乏的只是大量的測(cè)試(我做了幾下最簡(jiǎn)單的測(cè)試,慚愧!!^_^)
如果有問(wèn)題請(qǐng)聯(lián)系 yzx110@bit.edu.cn
相關(guān)文章
asp.net 將一個(gè)圖片以二進(jìn)制值的形式存入Xml文件中的實(shí)例代碼
這篇文章介紹了將一個(gè)圖片以二進(jìn)制值的形式存入Xml文件中的實(shí)例代碼,有需要的朋友可以參考一下2013-07-07
asp.net中生成縮略圖并添加版權(quán)實(shí)例代碼
這篇文章介紹了asp.net中生成縮略圖并添加版權(quán)實(shí)例代碼,有需要的朋友可以參考一下2013-11-11
ASP.NET?Core中MVC模式實(shí)現(xiàn)路由二
這篇文章介紹了ASP.NET?Core中MVC模式實(shí)現(xiàn)路由的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
[譯]ASP.NET Core 2.0 網(wǎng)址重定向的方法
本篇文章主要介紹了[譯]ASP.NET Core 2.0 網(wǎng)址重定向的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
.NET?Core利用BsonDocumentProjectionDefinition和Lookup進(jìn)行?join?
這篇文章主要介紹了.NET?Core利用BsonDocumentProjectionDefinition和Lookup進(jìn)行join關(guān)聯(lián)查詢(xún),這里主要介紹一下查詢(xún)角色的所有用戶(hù)的例子,文章結(jié)合實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下2022-10-10
.NET微服務(wù)架構(gòu)CI/CD自動(dòng)打包鏡像
這篇文章介紹了.NET使用微服務(wù)架構(gòu)CI/CD自動(dòng)打包鏡像的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01

