`
happmaoo
  • 浏览: 4345916 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

可扩展的SockBase设计和实现

阅读更多

可扩展的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

分享到:
评论

相关推荐

    基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip

    基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip基于Android Studio的个人记账应用帮助用户轻松管理和跟踪他们的财务源码.zip

    基于python实现树莓派和传感器的植物生长环境评估信息系统

    【作品名称】:基于python实现树莓派和传感器的植物生长环境评估信息系统 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:基于python实现树莓派和传感器的植物生长环境评估信息系统

    优质资源,Yearning Mysql SQL审核平台

    Yearning Mysql SQL审核平台(使用go语言)

    c语言课程设计-职工资源管理系统.rar

    void displayMenu() { printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); printf("+ 职工资源管理系统 +\n"); printf("+ +\n"); printf("+ 1. 录入职工信息 +\n"); printf("+ 2. 显示全部职工信息 +\n"); printf("+ 3. 根据工号查询

    华为OD机试D卷 - 来自异国的客人 - 免费看解析和代码.html

    私信博主免费获取真题解析以及代码

    2024华为OD机试D卷 - 最长的指定瑕疵度的元音子串 - 免费看解析和代码.html

    私信博主免费获取真题解析以及代码

    基于nodejs电影交流网站(源码 + 说明文档)

    基于nodejs电影交流网站(源码 + 说明文档) 第二章 开发技术介绍 1 2.2.1 Nodejs技术 1 2.2.2 mysql数据库介绍 1 2.2.3 MySQL环境配置 1 2.2.4 B/S架构 2 2.2.5 Vue框架 2 第三章 系统分析 1 3.1 可行性分析 1 3.1.1 技术可行性 1 3.1.2操作可行性 1 3.1.3 经济可行性 1 3.2性能需求分析 1 3.3功能分析 2 第四章 系统设计 4 4.1功能结构 4 4.2 数据库设计 4 4.2.1 数据库E/R图 4 4.2.2 数据库表 5 第五章 系统功能实现 11 5.1系统功能模块 11 5.2后台登录模块 12 5.2.1管理员功能 13 5.2.2 用户功能 15 第六章 系统测试 16

    setuptools-0.9.8.tar.gz

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    setuptools-23.2.1.zip

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    setuptools-10.0.zip

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    App工具查看md5、公钥等信息

    App工具查看md5、公钥等信息

    2024华为OD机试D卷 - 高效的任务规划 - 免费看解析和代码.html

    私信博主免费获取真题解析以及代码

    基于co-revDSD方法的计算程序

    基于co-revDSD方法的计算程序

    setuptools-54.0.0-py3-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    课程设计 基于FPGA的电子表源码+全部资料齐全.zip

    【资源说明】 课程设计 基于FPGA的电子表源码+全部资料齐全.zip课程设计 基于FPGA的电子表源码+全部资料齐全.zip 【备注】 1、该项目是高分课程设计项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过mac/window10/11/linux测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(如软件工程、计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也可作为课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    Fig0309.tif

    Fig0309.tif

    setuptools-5.0.zip

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    setuptools-8.0.1.tar.gz

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    华为OD机试D卷 - 连续字母长度 - 免费看解析和代码.html

    私信博主免费获取真题解析以及代码

    第十章 Python标准库(jupyter版 人工智能编程基础)

    第十章 Python标准库(jupyter版 人工智能编程基础)

Global site tag (gtag.js) - Google Analytics