可扩展的SockBase设计和实现(1)
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
目录
摘要
基于Sockets网络编程存在的问题
可扩展的SockBase设计
SockBase的编程实现
从SockBase继承及其使用方法
摘要
System.Net 命名空间为当前网络上使用的多种协议提供了简单的编程接口,如果需要底层控制更多的编程而言,开发人员就需要使用System.Net.Sockets 命名空间了。System.Net.Sockets为需要严密控制网络访问的开发人员提供了 Windows Sockets (Winsock) 接口的托管实现。 但是Sockets编程既烦杂,又毫无可扩展性,需要开发人员自己控制消息的接受和发送以及处理,这些与业务逻辑有关的工作在编程之时就需要写入代码,一旦需求发生变化,又得改写Sockets的接受消息列表和处理。同时对于命令字符串的构造都需要底层的程序员去控制,不仅容易出错,而且不易改变。面对复杂多变的业务逻辑,这样的架构毫无可重用而言,同时给程序员提出了很高的要求,很大程度的工作量放在了做底层的重复性的劳动上。因此,为了提供一种易于扩展的Sockets编程架构,使得开发人员将注意力放在业务逻辑上,我们提出了设计可扩展的SockBase思路,同时实现了这个架构,经验表明,不仅解决了上述存在的问题,而且取得了非常好的效果。
基于Sockets网络编程存在的问题
在一般的基于Sockets网络编程中,不难出现以下代码:
while(sock != null){
temp=ReadMsg(); //调用sock.Recevie(..)函数,把byte[]转成字符串
if( temp.Trim() == "Login")
{
// do some thing…
sock.Send( TransMsg("OK"));
}
else if (temp.Trim() == "show")
{
// do some thing…
sock.Send( TransMsg(ips));
}
else if (temp.Trim() == "Upload"){
// do some thing…
sock.Send(TransMsg("OK"));
// do some thing…
sock.Send(TransMsg("OK"));
}
else if (temp.Trim() == "list"){
// do some thing…
sock.Send(TransMsg(files));
}
else if (temp.Trim() == "Get"){
// do some thing…
sock.Send(TransMsg("OK"));
temp = ReadMsg().Trim();
// do some thing…
}
}
从上面的代码中,我们可以注意到,对于所有的从客户端发来的消息,都是统一在这个while()循环中进行处理的…
对于消息命令的接收,显然一般都是和上面的代码方式类似,统一放到一个地方来执行.但是上述代码对于消息的派发是使用的Switch case的结构.这样就带来一个问题.Switch Case是在程序代码编写阶段写的,也就是所谓的硬性编入.即在程序运行过程中不可修改.这样就使得程序不能在运行过程中对用户不同的输入/不同的条件发送不同的消息,或是用户自定义的,或是程序完成后新加入的扩展的命令..同时,也还是由于Switch case结构,使得对于消息的处理也固定下来了,同样也不能动态的去修改消息处理函数.这样使得程序的扩展性很差,而且对于底层的如上述代码,对于Socket的操作,完全不能直接使用到别的软件中.(因为消息命令,处理函数不一定是完全一样的).
也就是说,在通常的Sockets的网络开发中,开发人员自己控制消息的接受和发送以及处理,这些与业务逻辑有关的工作在编程之时就需要写入代码,一旦需求发生变化,又得改写Sockets的接受消息列表和处理。同时对于命令字符串的构造都需要底层的程序员去控制,不仅容易出错,而且不易改变。面对复杂多变的业务逻辑,这样的架构毫无可重用而言,同时给程序员提出了很高的要求,很大程度的工作量放在了做底层的重复性的劳动上。
可扩展的SockBase设计
针对上面的问题,我们提出了可扩展的SockBase.可扩展性主要在于能接收任意的消息,而且能对同一个消息在不同的情况下面有不同的处理函数..
我们想到了Windows的消息处理机制.当我们要处理一个系统消息的时候,或是处理我们自定义的消息的时候,首先,我们把自定义消息加入到程序的消息列表中去,同时通过Windows编程中的消息映射的方式,运行增加对处理此消息的函数.使操作系统在收到这个消息后,能够找到我们对其进行绑定的消息处理函数,进而调用..
回到Sockets中来,我们先做出一个类似Windows消息映射表样的东西.其中有两个元素,一个就是收到的消息命令,另一个就是收到此消息后的处理函数,在程序开发者开发过程中,只要在具体的消息接收前先对消息映射表进行初始化,就够了.SockBase会自动的调用相应的消息处理函数.
SockBase的编程实现
上面的部分都是理论.现在我们开始完成SockBase的实现代码.
1.定义消息映射表
根据上面所提到的,需要有一个类似消息映射表的东西.这里,我们使用Hashtable来存储消息和处理函数的数据..由于Hashtable是一种键/值型的集合,所以我们把消息命令做为键,对应的消息处理函数做为值.由于消息有很多种,而且我们希望对于所有的消息,都能在一个地方去调用相应的处理函数.所以我们使用了.NET的委托做为Hashtable中的值.
定义的委托如下:
Public delegate Command(string args);
使用方法如下:
Hashtable Commands = new Hashtable();
Commands.Add( /*消息命令*/, new Command( /*具体的处理函数*/));
调用的时候只要
((Command)Commands[/*消息命令*/])(/*参数*/);
就可以了~
2,SockBase的具体实现
好,现在,关于消息映射表的准备工作已完成了.现在开始SockBase的实现:P
(1) 构造函数以及变量的声明,实现
public class SocketBase:IDisposable{
//待处理的命令处理集合
protected Hashtable m_CommandHandlerList;
protected NetworkStream readStream;
protected NetworkStream writeStream;
protected Socket m_sock;
//通过构造函数将Socket的实例传进来.
public SocketBase(Socket sock){
m_sock = sock;
readStream = new NetworkStream(m_sock);
writeStream = new NetworkStream(m_sock);
}
public void Dispose()
{
// 关闭本地套节子
try
{
if (m_sock!= null)
{
if(m_sock.Connected)
{
m_sock.Shutdown(SocketShutdown.Both);
m_sock.Close();
}
m_sock = null;
}
}
catch(Exception ex)
{
}
}
}
(2) 发送和接收函数
准备工作已完成了.现在就是我们开始对m_sock进行消息接收,以及对消息进行派发了.
首先是消息发送和接收.由于Socket的不确定性,所以很容易出现发送的多个消息在接收的时候混在一起了,所以我们决定每发一个消息就发送固定大小的包,接收时了接收相应大小的包.
在SockBase中定义一个包的固定大小:
private static int DefaulteBufferSize =5120;
public int BufferSize
{
get{
if(m_BufferSize!=0)
return m_BufferSize;
else
return DefaulteBufferSize;
}
set{m_BufferSize=value;}
}
再就是发送,接收函数
public string ReceiveMsg()
{
byte[] Recs=new byte[BufferSize];
int count = 0;
int num;
do {
num = ReadStream.Read(Recs,count,BufferSize-count);
if( num == 0){
throw new Exception("客户端不正常关闭");
}
count += num;
} while( count < BufferSize);
return System.Text.Encoding.GetEncoding(Encoding).GetString(Recs).Replace("\0","");
}
public void Send(string msg)
{
byte[] sender = new Byte[BufferSize];
byte[] temp = System.Text.Encoding.Unicode.GetBytes(msg) ;
Array.Copy( temp,sender,temp.Length);
WriteStream.Write(sender,0,sender.Length);
WriteStream.Flush();
}
(3) 消息派发函数
好了,下面就是对消息进行派发的函数了:
public void CmdHandler(string ClientMessage)
{
//解析出命令
string[] cmdList=ClientMessage.Split(‘;’);
string cmdText = "";
for(int i=1;i<cmdList.Length;i++)
{
if(i==cmdList.Length-1)
{
cmdText += cmdList[i];
}
else
{
cmdText += cmdList[i]+":";
}
}
//寻找合适的匹配处理
if(m_CommandHandlerList.ContainsKey( cmdList[0] ) ) {
( ( Command ) m_ConnamdHandlerList[ cmdList[0] ) ( cmdText);
}
}
我们通过对m_CommandHandlerList中所有的键(即注册的消息命令)进行判断,如果和接收到的消息的命令是相同的,就直接去调用存在此Hashtable中对应的值(即Command委托)..
(4) SockBase运行的起点
最后的部分,整个SockBase运行的起点:
public void ListenSocket()
{
try
{
while(m_sock!=null&&m_sock.Connected)
{
//截获消息,并作出相应的处理
CmdHandler(ReceiveMsg());
}
}
}
现在我们只要直接在m_CommandHandlerList中加入我们要处理的消息的命令和处理函数,再运行ListenSocket(),就可以对接收到的消息进行相应的处理了..
从SockBase继承及其使用方法
上面实现了SockBase的基本的构架.对于大部分的Sockets网络编程,都可适用.下面就是使用的方法..
这里,我们从SockBase直接继承而来一个Client_ListenThread.在此类中,我们通过构造函数,将相应的Socket的实例传给m_sock.再对消息映射表进行初始化,用一个线程专门运行ListenSockt来对接收到的消息进行派发,调用其处理函数.
public class Client_ListenThread : SocketBase
{
#region 所有字段包含命令字段
#endregion
#region 所有方法
public Client_ListenThread(Socket Client_socket) : base(socket)
{
LoadCommandHandlerList();
}
//装载所有的命令处理队列
public void LoadCommandHandlerList()
{
CommandHandlerItem.Add(“GetFile” , new Command(GetFileHandler);
CommandHandlerItem.Add(“FileOK”, Command(FileOKHandler);
}
//以下为所有命令处理函数
private void GetFileHandler(string cmdText)
{
//检查文件是否存在
if((new FileManager()).CheckFileExist(cmdTxt))
{
Send(“OK”);
}
else
{
Send(“Failure”);
}
}
private void FileOKHandler(string cmdText)
{
Dispose();
}
#endregion
}
通过下面这个函数将其运行:
listen_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
…
listen_socket.Listen(-1);
while(true){
Client_ListenThread clientthread=new Client_ListenThread(listen_socket.Accept());
if ( clientthread.Sock.Connected )
{
Thread fileThread = new Thread(new ThreadStart(clientthread.ListenSocket));
fileThread.IsBackground=true;
fileThread.Start();
}
}
总结
通过上述的SockBase,我们可以在不改变SockBase的前提下,对消息映射表进行动态的修改.这样使得开发人员将注意力放在业务逻辑上,极大的方便了基于Sockets的网络编程开发.
可扩展的SockBase设计和实现(2)
目录
摘要
使用Hashtable建立消息映射表的问题
消息映射类的设计和实现
消息映射类在SockBase中的使用
摘要
在上一篇文章<<可扩展的SockBase设计和实现(1)>>中,我们消息映射表是通过简单的Hashtable表来建立的.这样做,功能相对太简单,而且不便于扩展.而且Hashtable中的一些特性是我们不必要使用的.所以在这里,我们直接使用自定义的消息映射类(集合类CommandHandlerList和消息命令/处理函数类CommandHandler.)来建立消息映射表.
使用Hashtable建立消息映射表的问题
我们的消息映射表,要求是要一个消息命令,能对应着一个/或多个处理函数.同时对于存储整个消息映射表,要求能够很方便的增加/删除其中的条目.而且能够以比较方便的形式从表中找到消息对应的处理函数用来进行调用.
Hashtable是.NET Framework自带的一种键/值对集合. 当某个项目加入集合时,HashTable即调用键值的GetHashCode方法,由于所有的类都是从System.Objec继承的,所以调用该方法即可确定该类的哈希代码并且按该代码排序存储。从性能的角度看,因为键值搜索仅限于具有同样哈希代码的键值,所以HashTable能够很快地从集合中检索任意一个元素,从而减少了必须通过检查以发现匹配的键值的数量。然而,因为插入到集合中的每个对象-键值对都必须产生相应的哈希代码,所以项目插入的代价就有点高了。因此,HashTable主要运用在按照任意键值反复检索大量相对静态的数据这一场合下。
由于我们的消息全部都是字符串,所以对于对象的比较而言只要进行字符串的匹配,不需要通过Hashtable得到HashCode进行比较.同时,由于Hashtable只为键/值对,直接使用不能带来更大的扩展性.所以我们选择放弃直接使用Hashtable.使用我们自定义的类.
st
分享到:
相关推荐
安全隐患台账(模版).xls
【作品名称】:基于 Java+Mysql 实现的小型仓库管理系统-课程设计(含课设文档+源码) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:项目说明 1、项目结构:maven+mvc(M模型用的是mybatis技术) 2、项目模式:C/S(客户机/服务器)模式 3、编辑器:IDEA 2019.3.1 4、mysql版本号:5.1.38
项目简介: 本项目实现了一个基于VHDL(VHSIC硬件描述语言)的倒车雷达系统。倒车雷达用于检测车辆后方障碍物的距离,以辅助驾驶员安全倒车。系统通过超声波传感器检测距离,并使用LED显示或蜂鸣器提示障碍物的接近程度。 项目模块: 传感器接口模块: 处理超声波传感器的信号。 发送触发信号,接收回波信号。 计算回波时间,进而计算距离。 距离计算模块: 根据传感器回波时间计算距离。 处理和转换距离数据,准备用于显示和警报。 警报显示模块: 基于计算出的距离提供视觉和听觉警报。 使用LED显示不同的距离范围。 使用蜂鸣器发出不同频率的警报声。 控制模块: 控制各模块的协调工作。 管理超声波传感器的触发和数据采集周期。
试验检测仪器设备(参考标准、有证标准物质)一览表.doc
vuInhub靶场实战系列-Kioptrix Level #1
本资源是配套作者博客【stm32、ESP8266、华为云 搭建一个简单的物联网系统】
GPU:计算机图显核心,计算场景应用崛起
Web3.0:致力打造一个基于区块链技术、用户主导、去中心化的网络生态。在Web3.0中,用户为满足自身需求进行交互操作,并在交互中利用区块链技术,从而实现价值的创造、分配与流通。这样的整个用户交互、价值流通的过程就形成了Web3.0生态。相比Web2.0的平台中心化特征,Web3.0致力于实现用户所有、用户共建的“去中心化”网络生态。
行业报告
MQD企业大学建设思路与年度工作重点.pptx
Java语言基础入门教程 Java实训教程 4.类构造函数-this-静态属性方法-instanceof运算符共55页.pptx
centos 6 redhat 6 x86架构的openssh 9.7版本二进制rpm包 安全更新、升级安装新版本openssh 9.7版本,当前最新版本,修复安全漏洞。 2024年6月8日制作,内含ssh-copy-id命令
风传花信,雨濯春尘——中国人身险产品变迁史与未来展望 按照不同分类方法,人身险可以分为以下种类: 1)按保障责任划分:人寿保险、健康保险、意外伤害保险、年金保险; 2)按设计类型划分:普通型、分红型、投资连结型、万能型。 40 年间中国人身险产品历经多次变迁,从单一死亡风险保障到多元风险覆盖+兼备理财储蓄功能。
C08-我的笔记02.md
公司项目试验仪器设备台账.docx
transformer灵魂21问
YOLOv10的改进技术点主要体现在以下几个方面: 1.一致双分配策略(Consistent Dual Assignments): 1.YOLOv10采用了一致双分配策略,通过双重标签分配和匹配指标的一致性,实现了无需NMS(非最大抑制)的后处理训练。这既保证了训练阶段的丰富监督信息,又实现了高效的无NMS预测,提升了性能和速度。 2.在训练过程中,一对一头部与传统的一对多头部合并,两者共享相同的优化目标,但使用不同的匹配策略。一对多头部提供了丰富的监控信号,而一对一头部在推理过程中确保了高效、无NMS的预测。 2.整体效率和精度驱动的模型设计: 1.YOLOv10采用了整体效率和精度驱动的模型设计策略,从效率和精度两个角度对各种YOLO组件进行优化。 2.效率驱动型模型设计:通过使用深度可分离卷积的简化架构来减少计算开销,分离空间减少和信道增加减少计算成本并保留信息。同时,使用内在秩分析来识别和减少模型阶段的冗余,用更有效的结构代替复杂的块。 3.精度驱动的模型设计:通过增加深度阶、引入大型核卷积和部分自注意力模块来增强模型能力,提高性能。 3.性能与效率的提升: 1.YOLOv10
MeEdu 是一款基于 PHP 开发的线上网校系统。支持线上点播 | 知识付费 | 网校装修 | 数据统计 | 会员模块 | 角色管理等丰富功能。MeEdu 采用前后端分离模式,覆盖 PC | H5 端口。特点:系统稳定 | 功能丰富 | 界面优美 | 持续迭代。截止目前,已超过 1000+ 个人/企业用户选用 MeEdu 搭建了他们的独立网校平台。
《引爆流量_获客技术》实战演练方式,让你的生意客户裂变方式裂变式
试验材料留样期限统计表.docx