在C#中使用异步Socket编程实现TCP网络服务的CS的通讯构架一基础类库部分.docx
- 文档编号:11952386
- 上传时间:2023-04-16
- 格式:DOCX
- 页数:52
- 大小:27.49KB
在C#中使用异步Socket编程实现TCP网络服务的CS的通讯构架一基础类库部分.docx
《在C#中使用异步Socket编程实现TCP网络服务的CS的通讯构架一基础类库部分.docx》由会员分享,可在线阅读,更多相关《在C#中使用异步Socket编程实现TCP网络服务的CS的通讯构架一基础类库部分.docx(52页珍藏版)》请在冰豆网上搜索。
在C#中使用异步Socket编程实现TCP网络服务的CS的通讯构架一基础类库部分
标题:
在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架
(一)----基础类库部分
当看到.NET中TcpListener和TcpClient的时候,我非常高兴,那就是我想要的通讯模式
但是使用之后发现它们的力量太单薄了,我们需要一个更好的类库来替代它们.
下面提供了一些类,可以很好的完成Tcp的C/S通讯模式.在本文的第二部分,我将为大家介绍怎么使用它们
主要通过事件来现实整个的功能:
服务器的事件包括:
服务器满
新客户端连接
客户端关闭
接收到数据
客户端使用的事件包括:
已连接服务器
接收到数据
连接关闭
另外为了灵活的处理需求变化,还提供了编码器和报文解析器的实现方法.
注意:
该类库没有经过严格的测试,如出现Bug,请发送给我,我会觉得你的整个行为是对我的鼓励和支持.
*/
//////////////////////////////////////////////////////////////////////////////////////////
///
///(C)2003-2005C2217Studio
///保留所有权利
///
///文件名称:
TcpCSFramework.cs
///文件ID:
///编程语言:
C#
///文件说明:
提供TCP网络服务的C/S的通讯构架基础类
///(使用异步Socket编程实现)
///
///当前版本:
1.1
///替换版本:
1.0
///
///作者:
邓杨均
///EMail:
dyj057@
///创建日期:
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_v1.0.cs
///3.在TcpServer中修改自定义的hashtable为系统Hashtable类型
///
///
usingSystem;
usingSystem.Net.Sockets;
usingSystem.Net;
usingSystem.Text;
usingSystem.Diagnostics;
usingSystem.Collections;
namespaceIbms.Net.TcpCSFramework
{
///
///网络通讯事件模型委托
///
publicdelegatevoidNetEvent(objectsender,NetEventArgse);
///
///提供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生成,可能与编码规范不符
///
///原理:
///
///
///使用用法:
///
///例子:
///
///
publicclassTcpSvr
{
#region定义字段
///
///默认的服务器最大连接客户端端数据
///
publicconstintDefaultMaxClient=100;
///
///接收数据缓冲区大小64K
///
publicconstintDefaultBufferSize=64*1024;
///
///最大数据报文大小
///
publicconstintMaxDatagramSize=640*1024;
///
///报文解析器
///
privateDatagramResolver_resolver;
///
///通讯格式编码解码器
///
privateCoder_coder;
///
///服务器程序使用的端口
///
privateushort_port;
///
///服务器程序允许的最大客户端连接数
///
privateushort_maxClient;
///
///服务器的运行状态
///
privatebool_isRun;
///
///接收数据缓冲区
///
privatebyte[]_recvDataBuffer;
///
///服务器使用的异步Socket类,
///
privateSocket_svrSock;
///
///保存所有客户端会话的哈希表
///
privateHashtable_sessionTable;
///
///当前的连接的客户端数
///
privateushort_clientCount;
#endregion
#region事件定义
///
///客户端建立连接事件
///
publiceventNetEventClientConn;
///
///客户端关闭事件
///
publiceventNetEventClientClose;
///
///服务器已经满事件
///
publiceventNetEventServerFull;
///
///服务器接收到数据事件
///
publiceventNetEventRecvData;
#endregion
#region构造函数
///
///构造函数
///
///
///
///
publicTcpSvr(ushortport,ushortmaxClient,Codercoder)
{
_port=port;
_maxClient=maxClient;
_coder=coder;
}
///
///构造函数(默认使用Default编码方式)
///
///
///
publicTcpSvr(ushortport,ushortmaxClient)
{
_port=port;
_maxClient=maxClient;
_coder=newCoder(Coder.EncodingMothord.Default);
}
//
///构造函数(默认使用Default编码方式和DefaultMaxClient(100)个客户端的容量)
///
///
publicTcpSvr(ushortport):
this(port,DefaultMaxClient)
{
}
#endregion
#region属性
///
///服务器的Socket对象
///
publicSocketServerSocket
{
get
{
return_svrSock;
}
}
///
///数据报文分析器
///
publicDatagramResolverResovlver
{
get
{
return_resolver;
}
set
{
_resolver=value;
}
}
///
///客户端会话数组,保存所有的客户端,不允许对该数组的内容进行修改
///
publicHashtableSessionTable
{
get
{
return_sessionTable;
}
}
///
///服务器可以容纳客户端的最大能力
///
publicintCapacity
{
get
{
return_maxClient;
}
}
///
///当前的客户端连接数
///
publicintSessionCount
{
get
{
return_clientCount;
}
}
///
///服务器运行状态
///
publicboolIsRun
{
get
{
return_isRun;
}
}
#endregion
#region公有方法
///
///启动服务器程序,开始监听客户端请求
///
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;
}
///
///停止服务器程序,所有与客户端的连接将关闭
///
publicvirtualvoidStop()
{
if(!
_isRun)
{
throw(newApplicationException("TcpSvr已经停止"));
}
//这个条件语句,一定要在关闭所有客户端以前调用
//否则在EndConn会出现错误
_isRun=false;
//关闭数据连接,负责客户端会认为是强制关闭连接
if(_svrSock.Connected)
{
_svrSock.Shutdown(SocketShutdown.Both);
}
CloseAllClient();
//清理资源
_svrSock.Close();
_sessionTable=null;
}
///
///关闭所有的客户端会话,与所有的客户端连接会断开
///
publicvirtualvoidCloseAllClient()
{
foreach(Sessionclientin_sessionTable.Values)
{
client.Close();
}
_sessionTable.Clear();
}
///
///关闭一个与客户端之间的会话
///
///
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();
}
}
///
///发送数据
///
///
///
publicvirtualvoidSend(SessionrecvDataClient,stringdatagram)
{
//获得数据编码
byte[]data=_coder.GetEncodingBytes(datagram);
recvDataClient.ClientSocket.BeginSend(data,0,data.Length,SocketFlags.None,
newAsyncCallback(SendDataEnd),recvDataClient.ClientSocket);
}
#endregion
#region受保护方法
///
///关闭一个客户端Socket,首先需要关闭Session
///
///
///
protectedvirtualvoidCloseClient(Socketclient,Session.ExitTypeexitType)
{
Debug.Assert(client!
=null);
//查找该客户端是否存在,如果不存在,抛出异常
SessioncloseClient=FindSession(client);
closeClient.TypeOfExit=exitType;
if(closeClient!
=null)
{
CloseSession(closeClient);
}
else
{
throw(newApplicationException("需要关闭的Socket对象不存在"));
}
}
///
///客户端连接处理函数
///
///
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);
}
///
///通过Socket对象查找Session对象
///
///
///
privateSessionFindSession(Socketclient)
{
SessionIdid=newSessionId((int)client.Handle);
return(Session)_sessionTable[id];
}
///
///接受数据完成处理函数,异步的特性就体现在这个函数中,
///收到数据后,会自动解析为字符串报文
///
///
protectedvirtualvoidReceiveData(IAsyncResultiar)
{
Socketclient=(Socket)iar.AsyncState;
try
{
//如果两次
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 使用 异步 Socket 编程 实现 TCP 网络服务 CS 通讯 构架 基础 部分