C使用异步Socket编程实现TCP网络服务的CS的通讯构架基础类库部分doc(完整版)_第1页
C使用异步Socket编程实现TCP网络服务的CS的通讯构架基础类库部分doc(完整版)_第2页
C使用异步Socket编程实现TCP网络服务的CS的通讯构架基础类库部分doc(完整版)_第3页
C使用异步Socket编程实现TCP网络服务的CS的通讯构架基础类库部分doc(完整版)_第4页
C使用异步Socket编程实现TCP网络服务的CS的通讯构架基础类库部分doc(完整版)_第5页
已阅读5页,还剩93页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C使用异步Socket编程实现TCP网络服务的CS的通讯构架基础类库部分doc(完整版)(文档可以直接使用,也可根据实际需要修改使用,可编辑欢迎下载)

在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)基础类库部分C使用异步Socket编程实现TCP网络服务的CS的通讯构架基础类库部分doc(完整版)(文档可以直接使用,也可根据实际需要修改使用,可编辑欢迎下载)

//////////////////////////////////////////////////////////////////////////////////////////

/*标题:在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)基础类库部分当看到.NET中TcpListener和TcpClient的时候,我非常高兴,那就是我想要的通讯模式

但是使用之后发现它们的力量太单薄了,我们需要一个更好的类库来替代它们.下面提供了一些类,可以很好的完成Tcp的C/S通讯模式.在本文的第二部分,我将为大家介绍怎么使用它们主要通过事件来现实整个的功能:

服务器的事件包括:服务器满

新客户端连接

客户端关闭

接收到数据

客户端使用的事件包括:已连接服务器

接收到数据

连接关闭另外为了灵活的处理需求变化,还提供了编码器和报文解析器的实现方法.

注意:该类库没有经过严格的测试,如出现Bug,请发送给我,我会觉得你的整个行为是对我的鼓励和支持.*/

/////////////////////////////////////////////////////////////////////////////////////////////<summary>

///(C)2003-2005C2217Studio

///保留所有权利

///

///文件名称:

TcpCSFramework.cs

///文件ID:

///编程语言:

C#

///文件说明:

提供TCP网络服务的C/S的通讯构架基础类

///

(使用异步Socket编程实现)

///

///当前版本:

1.1

///替换版本:

1.0

///

///作者:

邓杨均

///EMail:

dyj057@gmail

///创建日期:

2005-3-9

///最后修改日期:

2005-3-17

///

///历史修改记录:

///

///时间:

2005-3-14

///修改内容:

///

1.创建Ibms.Net.TcpCSFramework命名空间和添加Session对象.

///

2.修改NetEventArgs类,以适应新添加对象.

///

3.添加了会话退出类型,更适合实际的情况.

///

注意:

///

*强制退出类型是应用程序直接结束,比如通过任务管理器结束

///

程序或者程序异常退出等,没有执行正常的退出方法而产生的.

///

*正常的退出类型是应用程序执行正常的退出的方法关键在于

///

需要调用Socket.Shutdown(SocketShutdown.Both)后才调用

///

Socket.Close()方法,而不是直接的调用Socket.Close()方法,

///

如果那样调用将产生强制退出类型.

///

///

时间:

2005-3-16

///

修改内容:

///

1.创建TcpCli,Coder,DatagramResover对象,把抽象和实现部分分离

///

2.文件版本修改为1.1,1.0版本仍然保留,更名为:

///

TcpCSFramework_vs

///

3.在TcpServer中修改自定义的hashtable为系统Hashtable类型

///

///</summary>usingSystem;

usingSystem.Net.Sockets;

usingSystem.Net;

usingSystem.Text;

usingSystem.Diagnostics;

usingSystem.Collections;namespaceIbms.Net.TcpCSFramework

{

///<summary>

///网络通讯事件模型委托

///</summary>

publicdelegatevoidNetEvent(objectsender,NetEventArgse);

///<summary>

///提供TCP连接服务的服务器类

///

///版本:

1.1

///替换版本:

1.0

///

///特点:

///1.使用hash表保存所有已连接客户端的状态,收到数据时能实现快速查找.每当

///有一个新的客户端连接就会产生一个新的会话(Session).该Session代表了客

///户端对象.

///2.使用异步的Socket事件作为基础,完成网络通讯功能.

///3.支持带标记的数据报文格式的识别,以完成大数据报文的传输和适应恶劣的网

///络环境.初步规定该类支持的最大数据报文为640K(即一个数据包的大小不能大于

///640K,否则服务器程序会自动删除报文数据,认为是非法数据),防止因为数据报文

///无限制的增长而倒是服务器崩溃

///4.通讯格式默认使用Encoding.Default格式这样就可以和以前32位程序的客户端

///通讯.也可以使用U-16和U-8的的通讯方式进行.可以在该DatagramResolver类的

///继承类中重载编码和解码函数,自定义加密格式进行通讯.总之确保客户端与服务

///器端使用相同的通讯格式

///5.使用C#nativecode,将来出于效率的考虑可以将C++代码写成的32位dll来代替

///C#核心代码,但这样做缺乏可移植性,而且是Unsafe代码(该类的C++代码也存在)

///6.可以限制服务器的最大登陆客户端数目

///7.比使用TcpListener提供更加精细的控制和更加强大异步数据传输的功能,可作为

///

TcpListener的替代类

///

8.使用异步通讯模式,完全不用担心通讯阻塞和线程问题,无须考虑通讯的细节

///

///注意:

///1.部分的代码由RationalXDE生成,可能与编码规范不符

///

///原理:

///

///

///使用用法:

///

///例子:

///

///</summary>

publicclassTcpSvr

{

#region定义字段

///<summary>

///默认的服务器最大连接客户端端数据

///</summary>

publicconstintDefaultMaxClient=100;

///<summary>

///接收数据缓冲区大小64K

///</summary>

publicconstintDefaultBufferSize=64*1024;

///<summary>

///最大数据报文大小

///</summary>

publicconstintMaxDatagramSize=640*1024;

///<summary>

///报文解析器

///</summary>

privateDatagramResolver_resolver;

///<summary>

///通讯格式编码解码器

///</summary>

privateCoder_coder;

///<summary>

///服务器程序使用的端口

///</summary>

privateushort_port;

///<summary>

///服务器程序允许的最大客户端连接数

///</summary>

privateushort_maxClient;

///<summary>

///服务器的运行状态

///</summary>

privatebool_isRun;

///<summary>

///接收数据缓冲区

///</summary>

privatebyte[]_recvDataBuffer;

///<summary>

///服务器使用的异步Socket类,

///</summary>

privateSocket_svrSock;

///<summary>

///保存所有客户端会话的哈希表

///</summary>

privateHashtable_sessionTable;

///<summary>

///当前的连接的客户端数

///</summary>

privateushort_clientCount;

#endregion

#region事件定义

///<summary>

///客户端建立连接事件

///</summary>

publicevent

NetEventClientConn;

///<summary>

///客户端关闭事件

///</summary>

publicevent

NetEventClientClose;

///<summary>

///服务器已经满事件

///</summary>

publicevent

NetEventServerFull;

///<summary>

///服务器接收到数据事件

///</summary>

publicevent

NetEventRecvData;

#endregion

#region构造函数

///<summary>

///构造函数

///</summary>

///<paramname="port">服务器端监听的端口号</param>

///<paramname="maxClient">服务器能容纳客户端的最大能力</param>

///<paramname="encodingMothord">通讯的编码方式</param>

publicTcpSvr(ushortport,ushortmaxClient,Codercoder)

{

_port=port;

_maxClient=maxClient;

_coder=coder;

}

///<summary>

///构造函数(默认使用Default编码方式)

///</summary>

///<paramname="port">服务器端监听的端口号</param>

///<paramname="maxClient">服务器能容纳客户端的最大能力</param>

publicTcpSvr(ushortport,ushortmaxClient)

{

_port=port;

_maxClient=maxClient;

_coder=newCoder(Coder.EncodingMothord.Default);

}

//<summary>

///构造函数(默认使用Default编码方式和DefaultMaxClient(100)个客户端的容量)

///</summary>

///<paramname="port">服务器端监听的端口号</param>

publicTcpSvr(ushortport):this(port,DefaultMaxClient)

{

}

#endregion

#region属性

///<summary>

///服务器的Socket对象

///</summary>

publicSocketServerSocket

{

get

{

return_svrSock;

}

}

///<summary>

///数据报文分析器

///</summary>

publicDatagramResolverResovlver

{

get

{

return_resolver;

}

set

{

_resolver=value;

}

}

///<summary>

///客户端会话数组,保存所有的客户端,不允许对该数组的内容进行修改

///</summary>

publicHashtableSessionTable

{

get

{

return_sessionTable;

}

}

///<summary>

///服务器可以容纳客户端的最大能力

///</summary>

publicintCapacity

{

get

{

return_maxClient;

}

}

///<summary>

///当前的客户端连接数

///</summary>

publicintSessionCount

{

get

{

return_clientCount;

}

}

///<summary>

///服务器运行状态

///</summary>

publicboolIsRun

{

get

{

return_isRun;

}

}

#endregion

#region公有方法

///<summary>

///启动服务器程序,开始监听客户端请求

///</summary>

publicvirtualvoidStart()

{

if(_isRun)

{

throw(newApplicationException("TcpSvr已经在运行."));

}

_sessionTable=newHashtable(53);

_recvDataBuffer=newbyte[DefaultBufferSize];

//初始化socket

_svrSock=newSocket(AddressFamily.InterNetwork,

SocketType.Stream,ProtocolType.Tcp);

//绑定端口

IPEndPointiep=newIPEndPoint(IPAddress.Any,_port);

_svrSock.Bind(iep);

//开始监听

_svrSock.Listen(5);

//设置异步方法接受客户端连接

_svrSock.BeginAccept(newAsyncCallback(AcceptConn),_svrSock);

_isRun=true;

}

///<summary>

///停止服务器程序,所有与客户端的连接将关闭

///</summary>

publicvirtualvoidStop()

{

if(!_isRun)

{

throw(newApplicationException("TcpSvr已经停止"));

}

//这个条件语句,一定要在关闭所有客户端以前调用

//否则在EndConn会出现错误

_isRun=false;

//关闭数据连接,负责客户端会认为是强制关闭连接

if(_svrSock.Connected)

{

_svrSock.Shutdown(SocketShutdown.Both);

}

CloseAllClient();

//清理资源

_svrSock.Close();

_sessionTable=null;

}

///<summary>

///关闭所有的客户端会话,与所有的客户端连接会断开

///</summary>

publicvirtualvoidCloseAllClient()

{

foreach(Sessionclientin_sessionTable.Values)

{

client.Close();

}

_sessionTable.Clear();

}

///<summary>

///关闭一个与客户端之间的会话

///</summary>

///<paramname="closeClient">需要关闭的客户端会话对象</param>

publicvirtualvoidCloseSession(SessioncloseClient)

{

Debug.Assert(closeClient!=null);

if(closeClient!=null)

{

closeClient.Datagram=null;

_sessionTable.Remove(closeClient.ID);

_clientCount--;

//客户端强制关闭链接

if(ClientClose!=null)

{

ClientClose(this,newNetEventArgs(closeClient));

}

closeClient.Close();

}

}

///<summary>

///发送数据

///</summary>

///<paramname="recvDataClient">接收数据的客户端会话</param>

///<paramname="datagram">数据报文</param>

publicvirtualvoidSend(SessionrecvDataClient,stringdatagram)

{

//获得数据编码

byte[]data=_coder.GetEncodingBytes(datagram);

recvDataClient.ClientSocket.BeginSend(data,0,data.Length,SocketFlags.None,

newAsyncCallback(SendDataEnd),recvDataClient.ClientSocket);

}

#endregion

#region受保护方法

///<summary>

///关闭一个客户端Socket,首先需要关闭Session

///</summary>

///<paramname="client">目标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("需要关闭的Socket对象不存在"));

}

}

///<summary>

///客户端连接处理函数

///</summary>

///<paramname="iar">欲建立服务器连接的Socket对象</param>

protectedvirtualvoidAcceptConn(IAsyncResultiar)

{

//如果服务器停止了服务,就不能再接收新的客户端

if(!_isRun)

{

return;

}

//接受一个客户端的连接请求

Socketoldserver=(Socket)iar.AsyncState;

Socketclient=oldserver.EndAccept(iar);

//检查是否达到最大的允许的客户端数目

if(_clientCount==_maxClient)

{

//服务器已满,发出通知

if(ServerFull!=null)

{

ServerFull(this,newNetEventArgs(newSession(client)));

}

}

else

{

SessionnewSession=newSession(client);

_sessionTable.Add(newSession.ID,newSession);

//客户端引用计数+1

_clientCount++;

//开始接受来自该客户端的数据

client.BeginReceive(_recvDataBuffer,0,_recvDataBuffer.Length,SocketFlags.None,

newAsyncCallback(ReceiveData),client);

//新的客户段连接,发出通知

if(ClientConn!=null)

{

ClientConn(this,newNetEventArgs(newSession));

}

}

//继续接受客户端

_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>

///接受数据完成处理函数,异步的特性就体现在这个函数中,

///收到数据后,会自动解析为字符串报文

///</summary>

///<paramname="iar">目标客户端Socket</param>

protectedvirtualvoidReceiveData(IAsyncResultiar)

{

Socketclient=(Socket)iar.AsyncState;

try

{

//如果两次开始了异步的接收,所以当客户端退出的时候

//会两次执行EndReceive

intrecv=client.EndReceive(iar);

if(recv==0)

{

//正常的关闭

CloseClient(client,Session.ExitType.NormalExit);

return;

}

stringreceivedData=_coder.GetEncodingString(_recvDataBuffer,recv);

//发布收到数据的事件

if(RecvData!=null)

{

SessionsendDataSession=FindSession(client);

Debug.Assert(sendDataSession!=null);

//如果定义了报文的尾标记,需要处理报文的多种情况

if(_resolver!=null)

{

if(sendDataSession.Datagram!=null&&

sendDataSession.Datagram.Length!=0)

{

//加上最后一次通讯剩余的报文片断

receivedData=sendDataSession.Datagram+receivedData;

}

string[]recvDatagrams=_resolver.Resolve(refreceivedData);

foreach(stringnewDatagraminrecvDatagrams)

{

//深拷贝,为了保持Datagram的对立性

ICloneablecopySession=(ICloneable)sendDataSession;

SessionclientSession=(Session)copySession.Clone();

clientSession.Datagram=newDatagram;

//发布一个报文消息

RecvData(this,newNetEventArgs(clientSession));

}

//剩余的代码片断,下次接收的时候使用

sendDataSession.Datagram=receivedData;

if(sendDataSession.Datagram.Length>MaxDatagramSize)

{

sendDataSession.Datagram=null;

}

}

//没有定义报文的尾标记,直接交给消息订阅者使用

else

{

ICloneablecopySession=(ICloneable)sendDataSession;

SessionclientSession=(Session)copySession.Clone();

clientSession.Datagram=receivedData;

RecvData(this,newNetEventArgs(clientSession));

}

}//endofif(RecvData!=null)

//继续接收来自来客户端的数据

client.BeginReceive(_recvDataBuffer,0,_recvDataBuffer.Length,SocketFlags.None,

newAsyncCallback(ReceiveData),client);

}

catch(SocketExceptionex)

{

//客户端退出

if(10054==ex.ErrorCode)

{

//客户端强制关闭

CloseClient(client,Session.ExitType.ExceptionExit);

}

}

catch(ObjectDisposedExceptionex)

{

//这里的实现不够优雅

//当调用CloseSession()时,会结束数据接收,但是数据接收

//处理中会调用intrecv=client.EndReceive(iar);

//就访问了CloseSession()已经处置的对象

//我想这样的实现方法也是无伤大雅的.

if(ex!=null)

{

ex=null;

//DoNothing;

}

}

}

///<summary>

///发送数据完成处理函数

///</summary>

///<paramname="iar">目标客户端Socket</param>

protectedvirtualvoidSendDataEnd(IAsyncResultiar)

{

Socketclient=(Socket)iar.AsyncState;

intsent=client.EndSend(iar);

}

#endregion

}

///<summary>

///提供Tcp网络连接服务的客户端类

///

///版本:

1.0

///替换版本:

///

///特征:

///原理:

///1.使用异步Socket通讯与服务器按照一定的通讯格式通讯,请注意与服务器的通

///讯格式一定要一致,否则可能造成服务器程序崩溃,整个问题没有克服,怎么从byte[]

///判断它的编码格式

///2.支持带标记的数据报文格式的识别,以完成大数据报文的传输和适应恶劣的网

///络环境.

///用法:

///注意:

///</summary>

publicclassTcpCli

{

#region字段

///<summary>

///客户端与服务器之间的会话类

///</summary>

privateSession_session;

///<summary>

///客户端是否已经连接服务器

///</summary>

privatebool_isConnected=false;

///<summary>

///接收数据缓冲区大小64K

///</summary>

publicconstintDefaultBufferSize=64*1024;

///<summary>

///报文解析器

///</summary>

privateDatagramResolver_resolver;

///<summary>

///通讯格式编码解码器

///</summary>

privateCoder_coder;

///<summary>

///接收数据缓冲区

///</summary>

privatebyte[]_recvDataBuffer=newbyte[DefaultBufferSize];

#endregion

#region事件定义

//需要订阅事件才能收到事件的通知,如果订阅者退出,必须取消订阅

///<summary>

///已经连接服务器事件

///</summary>

publiceventNetEventConnectedServer;

///<summary>

///接收到数据报文事件

///</summary>

publiceventNetEventReceivedDatagram;

///<summary>

///连接断开事件

///</summary>

publiceventNetEventDisConnectedServer;

#endregion

#region属性

///<summary>

///返回客户端与服务器之间的会话对象

///</summary>

publicSessionClientSession

{

get

{

return_session;

}

}

///<summary>

///返回客户端与服务器之间的连接状态

///</summary>

publicboolIsConnected

{

get

{

return_isConnected;

}

}

///<summary>

///数据报文分析器

///</summary>

publicDatagramResolverResovlver

{

get

{

return_resolver;

}

set

{

_resolver=value;

}

}

///<summary>

///编码解码器

///</summary>

publicCoderServerCoder

{

get

{

return_coder;

}

}

#endregion

#region公有方法

///<summary>

///默认构造函数,使用默认的编码格式

///</summary>

publicTcpCli()

{

_coder=newCoder(Coder.EncodingMothord.Default);

}

///<summary>

///构造函数,使用一个特定的编码器来初始化

///</summary>

///<paramname="_coder">报文编码器</param>

publicTcpCli(Codercoder)

{

_coder=coder;

}

///<summary>

///连接服务器

///</summary>

///<paramname="ip">服务器IP地址</param>

///<paramname="port">服务器端口</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>

///发送数据报文

///</summary>

///<paramname="datagram"></param>

publicvirtualvoidSend(stringdatagram)

{

if(datagram.Length==0)

{

return;

}

if(!_isConnected)

{

throw(new

ApplicationException("没有连接服务器,不能发送数据"));

}

//获得报文的编码字节

byte[]data=_coder.GetEncodingBytes(datagram);

_session.ClientSocket.BeginSend(data,0,data.Length,SocketFlags.None,

newAsyncCallback(SendDataEnd),_session.ClientSocket);

}

///<summary>

///关闭连接

///</summary>

publicvirtualvoidClose()

{

if(!_isConnected)

{

return;

}

_session.Close();

_session=null;

_isConnected=false;

}

#endregion

#region受保护方法

///<summary>

///数据发送完成处理函数

///</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);

//创建新的会话

_session=newSession(socket);

_isConnected=true;

//触发连接建立事件

if(ConnectedServer!=null)

{

ConnectedServer(this,newNetEventArgs(_session));

}

//建立连接后应该立即接收数据

_session.ClientSocket.BeginReceive(_recvDataBuffer,0,

DefaultBufferSize,SocketFlags.None,

newAsyncCallback(RecvData),socket);

}

///<summary>

///数据接收处理函数

///</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);

//通过事件发布收到的报文

if(ReceivedDatagram!=null)

{

//通过报文解析器分析出报文

//如果定义了报文的尾标记,需要处理报文的多种情况

if(_resolver!=null)

{

if(_session.Datagram!=null&&

_session.Datagram.Length!=0)

{

//加上最后一次通讯剩余的报文片断

receivedData=_session.Datagram+receivedData;

}

string[]recvDatagrams=_resolver.Resolve(refreceivedData);

foreach(stringnewDatagraminrecvDatagrams)

{

//NeedDeepCopy.因为需要保证多个不同报文独立存在

ICloneablecopySession=(ICloneable)_session;

SessionclientSession=(Session)copySession.Clone();

clientSession.Datagram=newDatagram;

//发布一个报文消息

ReceivedDatagram(this,newNetEventArgs(clientSession));

}

//剩余的代码片断,下次接收的时候使用

_session.Datagram=receivedData;

}

//没有定义报文的尾标记,直接交给消息订阅者使用

else

{

ICloneablecopySession=(ICloneable)_session;

SessionclientSession=(Session)copySession.Clone();

clientSession.Datagram=receivedData;

ReceivedDatagram(this,newNetEventArgs(clientSession));

}

}//endofif(ReceivedDatagram!=null)

//继续接收数据

_session.ClientSocket.BeginReceive(_recvDataBuffer,0,DefaultBufferSize,SocketFlags.None,

newAsyncCallback(RecvData),_session.ClientSocket);

}

catch(SocketExceptionex)

{

//客户端退出

if(10054==ex.ErrorCode)

{

//服务器强制的关闭连接,强制退出

_session.TypeOfExit=Session.ExitType.ExceptionExit;

if(DisConnectedServer!=null)

{

DisConnectedServer(this,newNetEventArgs(_session));

}

}

else

{

throw(ex);

}

}

catch(ObjectDisposedExceptionex)

{

//这里的实现不够优雅

//当调用CloseSession()时,会结束数据接收,但是数据接收

//处理中会调用intrecv=client.EndReceive(iar);

//就访问了CloseSession()已经处置的对象

//我想这样的实现方法也是无伤大雅的.

if(ex!=null)

{

ex=null;

//DoNothing;

}

}

}

#endregion

}

///<summary>

///通讯编码格式提供者,为通讯服务提供编码和解码服务

///你可以在继承类中定制自己的编码方式如:数据加密传输等

///</summary>

publicclassCoder

{

///<summary>

///编码方式

///</summary>

privateEncodingMothord_encodingMothord;

protectedCoder()

{

}

publicCoder(EncodingMothordencodingMothord)

{

_encodingMothord=encodingMothord;

}

publicenumEncodingMothord

{

Default=0,

Unicode,

UTF8,

ASCII,

}

///<summary>

///通讯数据解码

///</summary>

///<paramname="dataBytes">需要解码的数据</param>

///<returns>编码后的数据</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>

///数据编码

///</summary>

///<paramname="datagram">需要编码的报文</param>

///<returns>编码后的数据</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>

///数据报文分析器,通过分析接收到的原始数据,得到完整的数据报文.

///继承该类可以实现自己的报文解析方法.

///通常的报文识别方法包括:固定长度,长度标记,标记符等方法

///本类的现实的是标记符的方法,你可以在继承类中实现其他的方法

///</summary>

publicclassDatagramResolver

{

///<summary>

///报文结束标记

///</summary>

privatestringendTag;

///<summary>

///返回结束标记

///</summary>

stringEndTag

{

get

{

returnendTag;

}

}

///<summary>

///受保护的默认构造函数,提供给继承类使用

///</summary>

protectedDatagramResolver()

{

}

///<summary>

///构造函数

///</summary>

///<paramname="endTag">报文结束标记</param>

publicDatagramResolver(stringendTag)

{

if(endTag==null)

{

throw(newArgumentNullException("结束标记不能为null"));

}

if(endTag=="")

{

throw(newArgumentException("结束标记符号不能为空字符串"));

}

this.endTag=endTag;

}

///<summary>

///解析报文

///</summary>

///<paramname="rawDatagram">原始数据,返回未使用的报文片断,

///该片断会保存在Session的Datagram对象中</param>

///<returns>报文数组,原始数据可能包含多个报文</returns>

publicvirtualstring[]Resolve(refstringrawDatagram)

{

ArrayListdatagrams

=newArrayList();

//末尾标记位置索引

inttagIndex=-1;

while(true)

{

tagIndex=rawDatagram.IndexOf(endTag,tagIndex+1);

if(tagIndex==-1)

{

break;

}

else

{

//按照末尾标记把字符串分为左右两个部分

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>

///客户端与服务器之间的会话类

///

///版本:

1.1

///替换版本:

1.0

///

///说明:

///

会话类包含远程通讯端的状态,这些状态包括Socket,报文内容,

///

客户端退出的类型(正常关闭,强制退出两种类型)

///</summary>

publicclassSession:ICloneable

{

#region字段

///<summary>

///会话ID

///</summary>

privateSessionId_id;

///<summary>

///客户端发送到服务器的报文

///注意:在有些情况下报文可能只是报文的片断而不完整

///</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>

///存取会话的报文

///</summary>

publicstringDatagram

{

get

{

return_datagram;

}

set

{

_datagram=value;

}

}

///<summary>

///获得与客户端会话关联的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>

///返回两个Session是否代表同一个客户端

///</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>

///构造函数

///</summary>

///<paramname="cliSock">会话使用的Socket连接</param>

publicSession(SocketcliSock)

{

Debug.Assert(cliSock!=null);

_cliSock=cliSock;

_id=newSessionId((int)cliSock.Handle);

}

///<summary>

///关闭会话

///</summary>

publicvoidClose()

{

Debug.Assert(_cliSock!=null);

//关闭数据的接受和发送

_cliSock.Shutdown(SocketShutdown.Both);

//清理资源

_cliSock.Close();

}

#endregion

#regionICloneable成员

objectSystem.ICloneable.Clone()

{

SessionnewSession=newSession(_cliSock);

newSession.Datagram=_datagram;

newSession.TypeOfExit=_exitType;

returnnewSession;

}

#endregion

}

///<summary>

///唯一的标志一个Session,辅助Session对象在Hash表中完成特定功能

///</summary>

publicclassSessionId

{

///<summary>

///与Session对象的Socket对象的Handle值相同,必须用这个值来初始化它

///</summary>

privateint_id;

///<summary>

///返回ID值

///</summary>

publicintID

{

get

{

return_id;

}

}

///<summary>

///构造函数

///</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>

///服务器程序的事件参数,包含了激发该事件的会话对象

///</summary>

publicclassNetEventArgs:EventArgs

{

#region字段

///<summary>

///客户端与服务器之间的会话

///</summary>

privateSession_client;

#endregion

#region构造函数

///<summary>

///构造函数

///</summary>

///<paramname="client">客户端会话</param>

publicNetEventArgs(

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论