C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第1頁
C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第2頁
C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第3頁
C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第4頁
C使用異步Socket編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)服務(wù)的CS的通訊構(gòu)架基礎(chǔ)類庫部分doc(完整版)_第5頁
已閱讀5頁,還剩93頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論