![C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第1頁](http://file4.renrendoc.com/view/36d479707cab7da0c99934249764c4dc/36d479707cab7da0c99934249764c4dc1.gif)
![C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第2頁](http://file4.renrendoc.com/view/36d479707cab7da0c99934249764c4dc/36d479707cab7da0c99934249764c4dc2.gif)
![C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第3頁](http://file4.renrendoc.com/view/36d479707cab7da0c99934249764c4dc/36d479707cab7da0c99934249764c4dc3.gif)
![C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第4頁](http://file4.renrendoc.com/view/36d479707cab7da0c99934249764c4dc/36d479707cab7da0c99934249764c4dc4.gif)
![C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第5頁](http://file4.renrendoc.com/view/36d479707cab7da0c99934249764c4dc/36d479707cab7da0c99934249764c4dc5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)(文檔可以直接使用,也可根據(jù)實(shí)際需要修改使用,可編輯歡迎下載)
在C#中使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的C/S的通訊構(gòu)架(一)基礎(chǔ)類庫部分C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)(文檔可以直接使用,也可根據(jù)實(shí)際需要修改使用,可編輯歡迎下載)
//////////////////////////////////////////////////////////////////////////////////////////
/*標(biāo)題:在C#中使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的C/S的通訊構(gòu)架(一)基礎(chǔ)類庫部分當(dāng)看到.NET中TcpListener和TcpClient的時(shí)候,我非常高興,那就是我想要的通訊模式
但是使用之后發(fā)現(xiàn)它們的力量太單薄了,我們需要一個(gè)更好的類庫來替代它們.下面提供了一些類,可以很好的完成Tcp的C/S通訊模式.在本文的第二部分,我將為大家介紹怎么使用它們主要通過事件來現(xiàn)實(shí)整個(gè)的功能:
服務(wù)器的事件包括:服務(wù)器滿
新客戶端連接
客戶端關(guān)閉
接收到數(shù)據(jù)
客戶端使用的事件包括:已連接服務(wù)器
接收到數(shù)據(jù)
連接關(guān)閉另外為了靈活的處理需求變化,還提供了編碼器和報(bào)文解析器的實(shí)現(xiàn)方法.
注意:該類庫沒有經(jīng)過嚴(yán)格的測試,如出現(xiàn)Bug,請發(fā)送給我,我會覺得你的整個(gè)行為是對我的鼓勵(lì)和支持.*/
/////////////////////////////////////////////////////////////////////////////////////////////<summary>
///(C)2003-2005C2217Studio
///保留所有權(quán)利
///
///文件名稱:
TcpCSFramework.cs
///文件ID:
///編程語言:
C#
///文件說明:
提供TCP網(wǎng)絡(luò)服務(wù)的C/S的通訊構(gòu)架基礎(chǔ)類
///
(使用異步Socket編程實(shí)現(xiàn))
///
///當(dāng)前版本:
1.1
///替換版本:
1.0
///
///作者:
鄧楊均
///EMail:
dyj057@gmail
///創(chuàng)建日期:
2005-3-9
///最后修改日期:
2005-3-17
///
///歷史修改記錄:
///
///時(shí)間:
2005-3-14
///修改內(nèi)容:
///
1.創(chuàng)建Ibms.Net.TcpCSFramework命名空間和添加Session對象.
///
2.修改NetEventArgs類,以適應(yīng)新添加對象.
///
3.添加了會話退出類型,更適合實(shí)際的情況.
///
注意:
///
*強(qiáng)制退出類型是應(yīng)用程序直接結(jié)束,比如通過任務(wù)管理器結(jié)束
///
程序或者程序異常退出等,沒有執(zhí)行正常的退出方法而產(chǎn)生的.
///
*正常的退出類型是應(yīng)用程序執(zhí)行正常的退出的方法關(guān)鍵在于
///
需要調(diào)用Socket.Shutdown(SocketShutdown.Both)后才調(diào)用
///
Socket.Close()方法,而不是直接的調(diào)用Socket.Close()方法,
///
如果那樣調(diào)用將產(chǎn)生強(qiáng)制退出類型.
///
///
時(shí)間:
2005-3-16
///
修改內(nèi)容:
///
1.創(chuàng)建TcpCli,Coder,DatagramResover對象,把抽象和實(shí)現(xiàn)部分分離
///
2.文件版本修改為1.1,1.0版本仍然保留,更名為:
///
TcpCSFramework_vs
///
3.在TcpServer中修改自定義的hashtable為系統(tǒng)Hashtable類型
///
///</summary>usingSystem;
usingSystem.Net.Sockets;
usingSystem.Net;
usingSystem.Text;
usingSystem.Diagnostics;
usingSystem.Collections;namespaceIbms.Net.TcpCSFramework
{
///<summary>
///網(wǎng)絡(luò)通訊事件模型委托
///</summary>
publicdelegatevoidNetEvent(objectsender,NetEventArgse);
///<summary>
///提供TCP連接服務(wù)的服務(wù)器類
///
///版本:
1.1
///替換版本:
1.0
///
///特點(diǎn):
///1.使用hash表保存所有已連接客戶端的狀態(tài),收到數(shù)據(jù)時(shí)能實(shí)現(xiàn)快速查找.每當(dāng)
///有一個(gè)新的客戶端連接就會產(chǎn)生一個(gè)新的會話(Session).該Session代表了客
///戶端對象.
///2.使用異步的Socket事件作為基礎(chǔ),完成網(wǎng)絡(luò)通訊功能.
///3.支持帶標(biāo)記的數(shù)據(jù)報(bào)文格式的識別,以完成大數(shù)據(jù)報(bào)文的傳輸和適應(yīng)惡劣的網(wǎng)
///絡(luò)環(huán)境.初步規(guī)定該類支持的最大數(shù)據(jù)報(bào)文為640K(即一個(gè)數(shù)據(jù)包的大小不能大于
///640K,否則服務(wù)器程序會自動(dòng)刪除報(bào)文數(shù)據(jù),認(rèn)為是非法數(shù)據(jù)),防止因?yàn)閿?shù)據(jù)報(bào)文
///無限制的增長而倒是服務(wù)器崩潰
///4.通訊格式默認(rèn)使用Encoding.Default格式這樣就可以和以前32位程序的客戶端
///通訊.也可以使用U-16和U-8的的通訊方式進(jìn)行.可以在該DatagramResolver類的
///繼承類中重載編碼和解碼函數(shù),自定義加密格式進(jìn)行通訊.總之確??蛻舳伺c服務(wù)
///器端使用相同的通訊格式
///5.使用C#nativecode,將來出于效率的考慮可以將C++代碼寫成的32位dll來代替
///C#核心代碼,但這樣做缺乏可移植性,而且是Unsafe代碼(該類的C++代碼也存在)
///6.可以限制服務(wù)器的最大登陸客戶端數(shù)目
///7.比使用TcpListener提供更加精細(xì)的控制和更加強(qiáng)大異步數(shù)據(jù)傳輸?shù)墓δ?可作為
///
TcpListener的替代類
///
8.使用異步通訊模式,完全不用擔(dān)心通訊阻塞和線程問題,無須考慮通訊的細(xì)節(jié)
///
///注意:
///1.部分的代碼由RationalXDE生成,可能與編碼規(guī)范不符
///
///原理:
///
///
///使用用法:
///
///例子:
///
///</summary>
publicclassTcpSvr
{
#region定義字段
///<summary>
///默認(rèn)的服務(wù)器最大連接客戶端端數(shù)據(jù)
///</summary>
publicconstintDefaultMaxClient=100;
///<summary>
///接收數(shù)據(jù)緩沖區(qū)大小64K
///</summary>
publicconstintDefaultBufferSize=64*1024;
///<summary>
///最大數(shù)據(jù)報(bào)文大小
///</summary>
publicconstintMaxDatagramSize=640*1024;
///<summary>
///報(bào)文解析器
///</summary>
privateDatagramResolver_resolver;
///<summary>
///通訊格式編碼解碼器
///</summary>
privateCoder_coder;
///<summary>
///服務(wù)器程序使用的端口
///</summary>
privateushort_port;
///<summary>
///服務(wù)器程序允許的最大客戶端連接數(shù)
///</summary>
privateushort_maxClient;
///<summary>
///服務(wù)器的運(yùn)行狀態(tài)
///</summary>
privatebool_isRun;
///<summary>
///接收數(shù)據(jù)緩沖區(qū)
///</summary>
privatebyte[]_recvDataBuffer;
///<summary>
///服務(wù)器使用的異步Socket類,
///</summary>
privateSocket_svrSock;
///<summary>
///保存所有客戶端會話的哈希表
///</summary>
privateHashtable_sessionTable;
///<summary>
///當(dāng)前的連接的客戶端數(shù)
///</summary>
privateushort_clientCount;
#endregion
#region事件定義
///<summary>
///客戶端建立連接事件
///</summary>
publicevent
NetEventClientConn;
///<summary>
///客戶端關(guān)閉事件
///</summary>
publicevent
NetEventClientClose;
///<summary>
///服務(wù)器已經(jīng)滿事件
///</summary>
publicevent
NetEventServerFull;
///<summary>
///服務(wù)器接收到數(shù)據(jù)事件
///</summary>
publicevent
NetEventRecvData;
#endregion
#region構(gòu)造函數(shù)
///<summary>
///構(gòu)造函數(shù)
///</summary>
///<paramname="port">服務(wù)器端監(jiān)聽的端口號</param>
///<paramname="maxClient">服務(wù)器能容納客戶端的最大能力</param>
///<paramname="encodingMothord">通訊的編碼方式</param>
publicTcpSvr(ushortport,ushortmaxClient,Codercoder)
{
_port=port;
_maxClient=maxClient;
_coder=coder;
}
///<summary>
///構(gòu)造函數(shù)(默認(rèn)使用Default編碼方式)
///</summary>
///<paramname="port">服務(wù)器端監(jiān)聽的端口號</param>
///<paramname="maxClient">服務(wù)器能容納客戶端的最大能力</param>
publicTcpSvr(ushortport,ushortmaxClient)
{
_port=port;
_maxClient=maxClient;
_coder=newCoder(Coder.EncodingMothord.Default);
}
//<summary>
///構(gòu)造函數(shù)(默認(rèn)使用Default編碼方式和DefaultMaxClient(100)個(gè)客戶端的容量)
///</summary>
///<paramname="port">服務(wù)器端監(jiān)聽的端口號</param>
publicTcpSvr(ushortport):this(port,DefaultMaxClient)
{
}
#endregion
#region屬性
///<summary>
///服務(wù)器的Socket對象
///</summary>
publicSocketServerSocket
{
get
{
return_svrSock;
}
}
///<summary>
///數(shù)據(jù)報(bào)文分析器
///</summary>
publicDatagramResolverResovlver
{
get
{
return_resolver;
}
set
{
_resolver=value;
}
}
///<summary>
///客戶端會話數(shù)組,保存所有的客戶端,不允許對該數(shù)組的內(nèi)容進(jìn)行修改
///</summary>
publicHashtableSessionTable
{
get
{
return_sessionTable;
}
}
///<summary>
///服務(wù)器可以容納客戶端的最大能力
///</summary>
publicintCapacity
{
get
{
return_maxClient;
}
}
///<summary>
///當(dāng)前的客戶端連接數(shù)
///</summary>
publicintSessionCount
{
get
{
return_clientCount;
}
}
///<summary>
///服務(wù)器運(yùn)行狀態(tài)
///</summary>
publicboolIsRun
{
get
{
return_isRun;
}
}
#endregion
#region公有方法
///<summary>
///啟動(dòng)服務(wù)器程序,開始監(jiān)聽客戶端請求
///</summary>
publicvirtualvoidStart()
{
if(_isRun)
{
throw(newApplicationException("TcpSvr已經(jīng)在運(yùn)行."));
}
_sessionTable=newHashtable(53);
_recvDataBuffer=newbyte[DefaultBufferSize];
//初始化socket
_svrSock=newSocket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
//綁定端口
IPEndPointiep=newIPEndPoint(IPAddress.Any,_port);
_svrSock.Bind(iep);
//開始監(jiān)聽
_svrSock.Listen(5);
//設(shè)置異步方法接受客戶端連接
_svrSock.BeginAccept(newAsyncCallback(AcceptConn),_svrSock);
_isRun=true;
}
///<summary>
///停止服務(wù)器程序,所有與客戶端的連接將關(guān)閉
///</summary>
publicvirtualvoidStop()
{
if(!_isRun)
{
throw(newApplicationException("TcpSvr已經(jīng)停止"));
}
//這個(gè)條件語句,一定要在關(guān)閉所有客戶端以前調(diào)用
//否則在EndConn會出現(xiàn)錯(cuò)誤
_isRun=false;
//關(guān)閉數(shù)據(jù)連接,負(fù)責(zé)客戶端會認(rèn)為是強(qiáng)制關(guān)閉連接
if(_svrSock.Connected)
{
_svrSock.Shutdown(SocketShutdown.Both);
}
CloseAllClient();
//清理資源
_svrSock.Close();
_sessionTable=null;
}
///<summary>
///關(guān)閉所有的客戶端會話,與所有的客戶端連接會斷開
///</summary>
publicvirtualvoidCloseAllClient()
{
foreach(Sessionclientin_sessionTable.Values)
{
client.Close();
}
_sessionTable.Clear();
}
///<summary>
///關(guān)閉一個(gè)與客戶端之間的會話
///</summary>
///<paramname="closeClient">需要關(guān)閉的客戶端會話對象</param>
publicvirtualvoidCloseSession(SessioncloseClient)
{
Debug.Assert(closeClient!=null);
if(closeClient!=null)
{
closeClient.Datagram=null;
_sessionTable.Remove(closeClient.ID);
_clientCount--;
//客戶端強(qiáng)制關(guān)閉鏈接
if(ClientClose!=null)
{
ClientClose(this,newNetEventArgs(closeClient));
}
closeClient.Close();
}
}
///<summary>
///發(fā)送數(shù)據(jù)
///</summary>
///<paramname="recvDataClient">接收數(shù)據(jù)的客戶端會話</param>
///<paramname="datagram">數(shù)據(jù)報(bào)文</param>
publicvirtualvoidSend(SessionrecvDataClient,stringdatagram)
{
//獲得數(shù)據(jù)編碼
byte[]data=_coder.GetEncodingBytes(datagram);
recvDataClient.ClientSocket.BeginSend(data,0,data.Length,SocketFlags.None,
newAsyncCallback(SendDataEnd),recvDataClient.ClientSocket);
}
#endregion
#region受保護(hù)方法
///<summary>
///關(guān)閉一個(gè)客戶端Socket,首先需要關(guān)閉Session
///</summary>
///<paramname="client">目標(biāo)Socket對象</param>
///<paramname="exitType">客戶端退出的類型</param>
protectedvirtualvoidCloseClient(Socketclient,Session.ExitTypeexitType)
{
Debug.Assert(client!=null);
//查找該客戶端是否存在,如果不存在,拋出異常
SessioncloseClient=FindSession(client);
closeClient.TypeOfExit=exitType;
if(closeClient!=null)
{
CloseSession(closeClient);
}
else
{
throw(newApplicationException("需要關(guān)閉的Socket對象不存在"));
}
}
///<summary>
///客戶端連接處理函數(shù)
///</summary>
///<paramname="iar">欲建立服務(wù)器連接的Socket對象</param>
protectedvirtualvoidAcceptConn(IAsyncResultiar)
{
//如果服務(wù)器停止了服務(wù),就不能再接收新的客戶端
if(!_isRun)
{
return;
}
//接受一個(gè)客戶端的連接請求
Socketoldserver=(Socket)iar.AsyncState;
Socketclient=oldserver.EndAccept(iar);
//檢查是否達(dá)到最大的允許的客戶端數(shù)目
if(_clientCount==_maxClient)
{
//服務(wù)器已滿,發(fā)出通知
if(ServerFull!=null)
{
ServerFull(this,newNetEventArgs(newSession(client)));
}
}
else
{
SessionnewSession=newSession(client);
_sessionTable.Add(newSession.ID,newSession);
//客戶端引用計(jì)數(shù)+1
_clientCount++;
//開始接受來自該客戶端的數(shù)據(jù)
client.BeginReceive(_recvDataBuffer,0,_recvDataBuffer.Length,SocketFlags.None,
newAsyncCallback(ReceiveData),client);
//新的客戶段連接,發(fā)出通知
if(ClientConn!=null)
{
ClientConn(this,newNetEventArgs(newSession));
}
}
//繼續(xù)接受客戶端
_svrSock.BeginAccept(newAsyncCallback(AcceptConn),_svrSock);
}
///<summary>
///通過Socket對象查找Session對象
///</summary>
///<paramname="client"></param>
///<returns>找到的Session對象,如果為null,說明并不存在該回話</returns>
privateSessionFindSession(Socketclient)
{
SessionIdid=new
SessionId((int)client.Handle);
return(Session)_sessionTable[id];
}
///<summary>
///接受數(shù)據(jù)完成處理函數(shù),異步的特性就體現(xiàn)在這個(gè)函數(shù)中,
///收到數(shù)據(jù)后,會自動(dòng)解析為字符串報(bào)文
///</summary>
///<paramname="iar">目標(biāo)客戶端Socket</param>
protectedvirtualvoidReceiveData(IAsyncResultiar)
{
Socketclient=(Socket)iar.AsyncState;
try
{
//如果兩次開始了異步的接收,所以當(dāng)客戶端退出的時(shí)候
//會兩次執(zhí)行EndReceive
intrecv=client.EndReceive(iar);
if(recv==0)
{
//正常的關(guān)閉
CloseClient(client,Session.ExitType.NormalExit);
return;
}
stringreceivedData=_coder.GetEncodingString(_recvDataBuffer,recv);
//發(fā)布收到數(shù)據(jù)的事件
if(RecvData!=null)
{
SessionsendDataSession=FindSession(client);
Debug.Assert(sendDataSession!=null);
//如果定義了報(bào)文的尾標(biāo)記,需要處理報(bào)文的多種情況
if(_resolver!=null)
{
if(sendDataSession.Datagram!=null&&
sendDataSession.Datagram.Length!=0)
{
//加上最后一次通訊剩余的報(bào)文片斷
receivedData=sendDataSession.Datagram+receivedData;
}
string[]recvDatagrams=_resolver.Resolve(refreceivedData);
foreach(stringnewDatagraminrecvDatagrams)
{
//深拷貝,為了保持Datagram的對立性
ICloneablecopySession=(ICloneable)sendDataSession;
SessionclientSession=(Session)copySession.Clone();
clientSession.Datagram=newDatagram;
//發(fā)布一個(gè)報(bào)文消息
RecvData(this,newNetEventArgs(clientSession));
}
//剩余的代碼片斷,下次接收的時(shí)候使用
sendDataSession.Datagram=receivedData;
if(sendDataSession.Datagram.Length>MaxDatagramSize)
{
sendDataSession.Datagram=null;
}
}
//沒有定義報(bào)文的尾標(biāo)記,直接交給消息訂閱者使用
else
{
ICloneablecopySession=(ICloneable)sendDataSession;
SessionclientSession=(Session)copySession.Clone();
clientSession.Datagram=receivedData;
RecvData(this,newNetEventArgs(clientSession));
}
}//endofif(RecvData!=null)
//繼續(xù)接收來自來客戶端的數(shù)據(jù)
client.BeginReceive(_recvDataBuffer,0,_recvDataBuffer.Length,SocketFlags.None,
newAsyncCallback(ReceiveData),client);
}
catch(SocketExceptionex)
{
//客戶端退出
if(10054==ex.ErrorCode)
{
//客戶端強(qiáng)制關(guān)閉
CloseClient(client,Session.ExitType.ExceptionExit);
}
}
catch(ObjectDisposedExceptionex)
{
//這里的實(shí)現(xiàn)不夠優(yōu)雅
//當(dāng)調(diào)用CloseSession()時(shí),會結(jié)束數(shù)據(jù)接收,但是數(shù)據(jù)接收
//處理中會調(diào)用intrecv=client.EndReceive(iar);
//就訪問了CloseSession()已經(jīng)處置的對象
//我想這樣的實(shí)現(xiàn)方法也是無傷大雅的.
if(ex!=null)
{
ex=null;
//DoNothing;
}
}
}
///<summary>
///發(fā)送數(shù)據(jù)完成處理函數(shù)
///</summary>
///<paramname="iar">目標(biāo)客戶端Socket</param>
protectedvirtualvoidSendDataEnd(IAsyncResultiar)
{
Socketclient=(Socket)iar.AsyncState;
intsent=client.EndSend(iar);
}
#endregion
}
///<summary>
///提供Tcp網(wǎng)絡(luò)連接服務(wù)的客戶端類
///
///版本:
1.0
///替換版本:
///
///特征:
///原理:
///1.使用異步Socket通訊與服務(wù)器按照一定的通訊格式通訊,請注意與服務(wù)器的通
///訊格式一定要一致,否則可能造成服務(wù)器程序崩潰,整個(gè)問題沒有克服,怎么從byte[]
///判斷它的編碼格式
///2.支持帶標(biāo)記的數(shù)據(jù)報(bào)文格式的識別,以完成大數(shù)據(jù)報(bào)文的傳輸和適應(yīng)惡劣的網(wǎng)
///絡(luò)環(huán)境.
///用法:
///注意:
///</summary>
publicclassTcpCli
{
#region字段
///<summary>
///客戶端與服務(wù)器之間的會話類
///</summary>
privateSession_session;
///<summary>
///客戶端是否已經(jīng)連接服務(wù)器
///</summary>
privatebool_isConnected=false;
///<summary>
///接收數(shù)據(jù)緩沖區(qū)大小64K
///</summary>
publicconstintDefaultBufferSize=64*1024;
///<summary>
///報(bào)文解析器
///</summary>
privateDatagramResolver_resolver;
///<summary>
///通訊格式編碼解碼器
///</summary>
privateCoder_coder;
///<summary>
///接收數(shù)據(jù)緩沖區(qū)
///</summary>
privatebyte[]_recvDataBuffer=newbyte[DefaultBufferSize];
#endregion
#region事件定義
//需要訂閱事件才能收到事件的通知,如果訂閱者退出,必須取消訂閱
///<summary>
///已經(jīng)連接服務(wù)器事件
///</summary>
publiceventNetEventConnectedServer;
///<summary>
///接收到數(shù)據(jù)報(bào)文事件
///</summary>
publiceventNetEventReceivedDatagram;
///<summary>
///連接斷開事件
///</summary>
publiceventNetEventDisConnectedServer;
#endregion
#region屬性
///<summary>
///返回客戶端與服務(wù)器之間的會話對象
///</summary>
publicSessionClientSession
{
get
{
return_session;
}
}
///<summary>
///返回客戶端與服務(wù)器之間的連接狀態(tài)
///</summary>
publicboolIsConnected
{
get
{
return_isConnected;
}
}
///<summary>
///數(shù)據(jù)報(bào)文分析器
///</summary>
publicDatagramResolverResovlver
{
get
{
return_resolver;
}
set
{
_resolver=value;
}
}
///<summary>
///編碼解碼器
///</summary>
publicCoderServerCoder
{
get
{
return_coder;
}
}
#endregion
#region公有方法
///<summary>
///默認(rèn)構(gòu)造函數(shù),使用默認(rèn)的編碼格式
///</summary>
publicTcpCli()
{
_coder=newCoder(Coder.EncodingMothord.Default);
}
///<summary>
///構(gòu)造函數(shù),使用一個(gè)特定的編碼器來初始化
///</summary>
///<paramname="_coder">報(bào)文編碼器</param>
publicTcpCli(Codercoder)
{
_coder=coder;
}
///<summary>
///連接服務(wù)器
///</summary>
///<paramname="ip">服務(wù)器IP地址</param>
///<paramname="port">服務(wù)器端口</param>
publicvirtualvoidConnect(stringip,intport)
{
if(IsConnected)
{
//重新連接
Debug.Assert(_session!=null);
Close();
}
Socketnewsock=newSocket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
IPEndPointiep=newIPEndPoint(IPAddress.Parse(ip),port);
newsock.BeginConnect(iep,newAsyncCallback(Connected),newsock);
}
///<summary>
///發(fā)送數(shù)據(jù)報(bào)文
///</summary>
///<paramname="datagram"></param>
publicvirtualvoidSend(stringdatagram)
{
if(datagram.Length==0)
{
return;
}
if(!_isConnected)
{
throw(new
ApplicationException("沒有連接服務(wù)器,不能發(fā)送數(shù)據(jù)"));
}
//獲得報(bào)文的編碼字節(jié)
byte[]data=_coder.GetEncodingBytes(datagram);
_session.ClientSocket.BeginSend(data,0,data.Length,SocketFlags.None,
newAsyncCallback(SendDataEnd),_session.ClientSocket);
}
///<summary>
///關(guān)閉連接
///</summary>
publicvirtualvoidClose()
{
if(!_isConnected)
{
return;
}
_session.Close();
_session=null;
_isConnected=false;
}
#endregion
#region受保護(hù)方法
///<summary>
///數(shù)據(jù)發(fā)送完成處理函數(shù)
///</summary>
///<paramname="iar"></param>
protectedvirtualvoidSendDataEnd(IAsyncResultiar)
{
Socketremote=(Socket)iar.AsyncState;
intsent=remote.EndSend(iar);
Debug.Assert(sent!=0);
}
///<summary>
///建立Tcp連接后處理過程
///</summary>
///<paramname="iar">異步Socket</param>
protectedvirtualvoidConnected(IAsyncResultiar)
{
Socketsocket=(Socket)iar.AsyncState;
socket.EndConnect(iar);
//創(chuàng)建新的會話
_session=newSession(socket);
_isConnected=true;
//觸發(fā)連接建立事件
if(ConnectedServer!=null)
{
ConnectedServer(this,newNetEventArgs(_session));
}
//建立連接后應(yīng)該立即接收數(shù)據(jù)
_session.ClientSocket.BeginReceive(_recvDataBuffer,0,
DefaultBufferSize,SocketFlags.None,
newAsyncCallback(RecvData),socket);
}
///<summary>
///數(shù)據(jù)接收處理函數(shù)
///</summary>
///<paramname="iar">異步Socket</param>
protectedvirtualvoidRecvData(IAsyncResultiar)
{
Socketremote=(Socket)iar.AsyncState;
try
{
intrecv=remote.EndReceive(iar);
//正常的退出
if(recv==0)
{
_session.TypeOfExit=Session.ExitType.NormalExit;
if(DisConnectedServer!=null)
{
DisConnectedServer(this,newNetEventArgs(_session));
}
return;
}
stringreceivedData=_coder.GetEncodingString(_recvDataBuffer,recv);
//通過事件發(fā)布收到的報(bào)文
if(ReceivedDatagram!=null)
{
//通過報(bào)文解析器分析出報(bào)文
//如果定義了報(bào)文的尾標(biāo)記,需要處理報(bào)文的多種情況
if(_resolver!=null)
{
if(_session.Datagram!=null&&
_session.Datagram.Length!=0)
{
//加上最后一次通訊剩余的報(bào)文片斷
receivedData=_session.Datagram+receivedData;
}
string[]recvDatagrams=_resolver.Resolve(refreceivedData);
foreach(stringnewDatagraminrecvDatagrams)
{
//NeedDeepCopy.因?yàn)樾枰WC多個(gè)不同報(bào)文獨(dú)立存在
ICloneablecopySession=(ICloneable)_session;
SessionclientSession=(Session)copySession.Clone();
clientSession.Datagram=newDatagram;
//發(fā)布一個(gè)報(bào)文消息
ReceivedDatagram(this,newNetEventArgs(clientSession));
}
//剩余的代碼片斷,下次接收的時(shí)候使用
_session.Datagram=receivedData;
}
//沒有定義報(bào)文的尾標(biāo)記,直接交給消息訂閱者使用
else
{
ICloneablecopySession=(ICloneable)_session;
SessionclientSession=(Session)copySession.Clone();
clientSession.Datagram=receivedData;
ReceivedDatagram(this,newNetEventArgs(clientSession));
}
}//endofif(ReceivedDatagram!=null)
//繼續(xù)接收數(shù)據(jù)
_session.ClientSocket.BeginReceive(_recvDataBuffer,0,DefaultBufferSize,SocketFlags.None,
newAsyncCallback(RecvData),_session.ClientSocket);
}
catch(SocketExceptionex)
{
//客戶端退出
if(10054==ex.ErrorCode)
{
//服務(wù)器強(qiáng)制的關(guān)閉連接,強(qiáng)制退出
_session.TypeOfExit=Session.ExitType.ExceptionExit;
if(DisConnectedServer!=null)
{
DisConnectedServer(this,newNetEventArgs(_session));
}
}
else
{
throw(ex);
}
}
catch(ObjectDisposedExceptionex)
{
//這里的實(shí)現(xiàn)不夠優(yōu)雅
//當(dāng)調(diào)用CloseSession()時(shí),會結(jié)束數(shù)據(jù)接收,但是數(shù)據(jù)接收
//處理中會調(diào)用intrecv=client.EndReceive(iar);
//就訪問了CloseSession()已經(jīng)處置的對象
//我想這樣的實(shí)現(xiàn)方法也是無傷大雅的.
if(ex!=null)
{
ex=null;
//DoNothing;
}
}
}
#endregion
}
///<summary>
///通訊編碼格式提供者,為通訊服務(wù)提供編碼和解碼服務(wù)
///你可以在繼承類中定制自己的編碼方式如:數(shù)據(jù)加密傳輸?shù)?/p>
///</summary>
publicclassCoder
{
///<summary>
///編碼方式
///</summary>
privateEncodingMothord_encodingMothord;
protectedCoder()
{
}
publicCoder(EncodingMothordencodingMothord)
{
_encodingMothord=encodingMothord;
}
publicenumEncodingMothord
{
Default=0,
Unicode,
UTF8,
ASCII,
}
///<summary>
///通訊數(shù)據(jù)解碼
///</summary>
///<paramname="dataBytes">需要解碼的數(shù)據(jù)</param>
///<returns>編碼后的數(shù)據(jù)</returns>
publicvirtualstringGetEncodingString(byte[]dataBytes,intsize)
{
switch(_encodingMothord)
{
caseEncodingMothord.Default:
{
returnEncoding.Default.GetString(dataBytes,0,size);
}
caseEncodingMothord.Unicode:
{
returnEncoding.Unicode.GetString(dataBytes,0,size);
}
caseEncodingMothord.UTF8:
{
returnEncoding.UTF8.GetString(dataBytes,0,size);
}
caseEncodingMothord.ASCII:
{
returnEncoding.ASCII.GetString(dataBytes,0,size);
}
default:
{
throw(newException("未定義的編碼格式"));
}
}
}
///<summary>
///數(shù)據(jù)編碼
///</summary>
///<paramname="datagram">需要編碼的報(bào)文</param>
///<returns>編碼后的數(shù)據(jù)</returns>
publicvirtualbyte[]GetEncodingBytes(stringdatagram)
{
switch(_encodingMothord)
{
caseEncodingMothord.Default:
{
returnEncoding.Default.GetBytes(datagram);
}
caseEncodingMothord.Unicode:
{
returnEncoding.Unicode.GetBytes(datagram);
}
caseEncodingMothord.UTF8:
{
returnEncoding.UTF8.GetBytes(datagram);
}
caseEncodingMothord.ASCII:
{
returnEncoding.ASCII.GetBytes(datagram);
}
default:
{
throw(newException("未定義的編碼格式"));
}
}
}
}
///<summary>
///數(shù)據(jù)報(bào)文分析器,通過分析接收到的原始數(shù)據(jù),得到完整的數(shù)據(jù)報(bào)文.
///繼承該類可以實(shí)現(xiàn)自己的報(bào)文解析方法.
///通常的報(bào)文識別方法包括:固定長度,長度標(biāo)記,標(biāo)記符等方法
///本類的現(xiàn)實(shí)的是標(biāo)記符的方法,你可以在繼承類中實(shí)現(xiàn)其他的方法
///</summary>
publicclassDatagramResolver
{
///<summary>
///報(bào)文結(jié)束標(biāo)記
///</summary>
privatestringendTag;
///<summary>
///返回結(jié)束標(biāo)記
///</summary>
stringEndTag
{
get
{
returnendTag;
}
}
///<summary>
///受保護(hù)的默認(rèn)構(gòu)造函數(shù),提供給繼承類使用
///</summary>
protectedDatagramResolver()
{
}
///<summary>
///構(gòu)造函數(shù)
///</summary>
///<paramname="endTag">報(bào)文結(jié)束標(biāo)記</param>
publicDatagramResolver(stringendTag)
{
if(endTag==null)
{
throw(newArgumentNullException("結(jié)束標(biāo)記不能為null"));
}
if(endTag=="")
{
throw(newArgumentException("結(jié)束標(biāo)記符號不能為空字符串"));
}
this.endTag=endTag;
}
///<summary>
///解析報(bào)文
///</summary>
///<paramname="rawDatagram">原始數(shù)據(jù),返回未使用的報(bào)文片斷,
///該片斷會保存在Session的Datagram對象中</param>
///<returns>報(bào)文數(shù)組,原始數(shù)據(jù)可能包含多個(gè)報(bào)文</returns>
publicvirtualstring[]Resolve(refstringrawDatagram)
{
ArrayListdatagrams
=newArrayList();
//末尾標(biāo)記位置索引
inttagIndex=-1;
while(true)
{
tagIndex=rawDatagram.IndexOf(endTag,tagIndex+1);
if(tagIndex==-1)
{
break;
}
else
{
//按照末尾標(biāo)記把字符串分為左右兩個(gè)部分
stringnewDatagram=rawDatagram.Substring(
0,tagIndex+endTag.Length);
datagrams.Add(newDatagram);
if(tagIndex+endTag.Length>=rawDatagram.Length)
{
rawDatagram="";
break;
}
rawDatagram=rawDatagram.Substring(tagIndex+endTag.Length,
rawDatagram.Length-newDatagram.Length);
//從開始位置開始查找
tagIndex=0;
}
}
string[]results=newstring[datagrams.Count];
datagrams.CopyTo(results);
returnresults;
}
}
///<summary>
///客戶端與服務(wù)器之間的會話類
///
///版本:
1.1
///替換版本:
1.0
///
///說明:
///
會話類包含遠(yuǎn)程通訊端的狀態(tài),這些狀態(tài)包括Socket,報(bào)文內(nèi)容,
///
客戶端退出的類型(正常關(guān)閉,強(qiáng)制退出兩種類型)
///</summary>
publicclassSession:ICloneable
{
#region字段
///<summary>
///會話ID
///</summary>
privateSessionId_id;
///<summary>
///客戶端發(fā)送到服務(wù)器的報(bào)文
///注意:在有些情況下報(bào)文可能只是報(bào)文的片斷而不完整
///</summary>
privatestring_datagram;
///<summary>
///客戶端的Socket
///</summary>
privateSocket_cliSock;
///<summary>
///客戶端的退出類型
///</summary>
privateExitType_exitType;
///<summary>
///退出類型枚舉
///</summary>
publicenumExitType
{
NormalExit,
ExceptionExit
};
#endregion
#region屬性
///<summary>
///返回會話的ID
///</summary>
publicSessionIdID
{
get
{
return_id;
}
}
///<summary>
///存取會話的報(bào)文
///</summary>
publicstringDatagram
{
get
{
return_datagram;
}
set
{
_datagram=value;
}
}
///<summary>
///獲得與客戶端會話關(guān)聯(lián)的Socket對象
///</summary>
publicSocketClientSocket
{
get
{
return_cliSock;
}
}
///<summary>
///存取客戶端的退出方式
///</summary>
publicExitTypeTypeOfExit
{
get
{
return_exitType;
}
set
{
_exitType=value;
}
}
#endregion
#region方法
///<summary>
///使用Socket對象的Handle值作為HashCode,它具有良好的線性特征.
///</summary>
///<returns></returns>
publicoverrideintGetHashCode()
{
return(int)_cliSock.Handle;
}
///<summary>
///返回兩個(gè)Session是否代表同一個(gè)客戶端
///</summary>
///<paramname="obj"></param>
///<returns></returns>
publicoverrideboolEquals(objectobj)
{
SessionrightObj=(Session)obj;
return(int)_cliSock.Handle==(int)rightObj.ClientSocket.Handle;
}
///<summary>
///重載ToString()方法,返回Session對象的特征
///</summary>
///<returns></returns>
publicoverridestringToString()
{
stringresult=string.Format("Session:{0},IP:{1}",
_id,_cliSock.RemoteEndPoint.ToString());
//result.C
returnresult;
}
///<summary>
///構(gòu)造函數(shù)
///</summary>
///<paramname="cliSock">會話使用的Socket連接</param>
publicSession(SocketcliSock)
{
Debug.Assert(cliSock!=null);
_cliSock=cliSock;
_id=newSessionId((int)cliSock.Handle);
}
///<summary>
///關(guān)閉會話
///</summary>
publicvoidClose()
{
Debug.Assert(_cliSock!=null);
//關(guān)閉數(shù)據(jù)的接受和發(fā)送
_cliSock.Shutdown(SocketShutdown.Both);
//清理資源
_cliSock.Close();
}
#endregion
#regionICloneable成員
objectSystem.ICloneable.Clone()
{
SessionnewSession=newSession(_cliSock);
newSession.Datagram=_datagram;
newSession.TypeOfExit=_exitType;
returnnewSession;
}
#endregion
}
///<summary>
///唯一的標(biāo)志一個(gè)Session,輔助Session對象在Hash表中完成特定功能
///</summary>
publicclassSessionId
{
///<summary>
///與Session對象的Socket對象的Handle值相同,必須用這個(gè)值來初始化它
///</summary>
privateint_id;
///<summary>
///返回ID值
///</summary>
publicintID
{
get
{
return_id;
}
}
///<summary>
///構(gòu)造函數(shù)
///</summary>
///<paramname="id">Socket的Handle值</param>
publicSessionId(intid)
{
_id=id;
}
///<summary>
///重載.為了符合Hashtable鍵值特征
///</summary>
///<paramname="obj"></param>
///<returns></returns>
publicoverrideboolEquals(objectobj)
{
if(obj!=null)
{
SessionIdright=(SessionId)obj;
return_id==right._id;
}
elseif(this==null)
{
returntrue;
}
else
{
returnfalse;
}
}
///<summary>
///重載.為了符合Hashtable鍵值特征
///</summary>
///<returns></returns>
publicoverrideintGetHashCode()
{
return_id;
}
///<summary>
///重載,為了方便顯示輸出
///</summary>
///<returns></returns>
publicoverridestringToString()
{
return_id.ToString();
}
}
///<summary>
///服務(wù)器程序的事件參數(shù),包含了激發(fā)該事件的會話對象
///</summary>
publicclassNetEventArgs:EventArgs
{
#region字段
///<summary>
///客戶端與服務(wù)器之間的會話
///</summary>
privateSession_client;
#endregion
#region構(gòu)造函數(shù)
///<summary>
///構(gòu)造函數(shù)
///</summary>
///<paramname="client">客戶端會話</param>
publicNetEventArgs(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年智能化高架活動(dòng)地板項(xiàng)目可行性研究報(bào)告
- 2025年排水閥門項(xiàng)目可行性研究報(bào)告
- 2025年大紅描金粉蠟箋項(xiàng)目可行性研究報(bào)告
- 2025年壓片機(jī)項(xiàng)目可行性研究報(bào)告
- 2025年全粒面填充項(xiàng)目可行性研究報(bào)告
- 2025年P(guān)VC可調(diào)電容項(xiàng)目可行性研究報(bào)告
- 2025至2030年中國陶瓷纖維澆注料數(shù)據(jù)監(jiān)測研究報(bào)告
- 2025至2030年中國轉(zhuǎn)動(dòng)計(jì)數(shù)器數(shù)據(jù)監(jiān)測研究報(bào)告
- 2025至2030年中國落地通風(fēng)柜數(shù)據(jù)監(jiān)測研究報(bào)告
- 2025至2030年樺木皮項(xiàng)目投資價(jià)值分析報(bào)告
- 2025年工貿(mào)企業(yè)春節(jié)復(fù)工復(fù)產(chǎn)方案
- 安防監(jiān)控工程施工方案(3篇)
- 2025年藍(lán)莓種苗行業(yè)深度研究分析報(bào)告
- 【道法】歷久彌新的思想理念課件 2024-2025學(xué)年統(tǒng)編版道德與法治七年級下冊
- 《糖尿病診療規(guī)范》課件
- 2024年初三數(shù)學(xué)競賽考試試題
- 飲品店操作流程圖
- 風(fēng)居住的街道鋼琴二胡合奏譜
- PADS元件封裝制作規(guī)范要點(diǎn)
- 膠水行業(yè)中最常用的英文術(shù)語
- citrix桌面虛擬化平臺健康檢查指南10
評論
0/150
提交評論