一、分布式消息总线

在很多MIS项目之中都有这样的需求,需要一个及时、高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已经完成,在通常的情况下,开发人中都是在使用者B所使用的程序之中写数据库轮循代码,这样就会产品一个很严重的两个问题,第一个问题是延迟,轮循机制要定时执行,必须会引起延迟,第二个问题是数据库压力过大,当进行高频度的轮循会生产大量的数据库查询,并且如果有大量的使用者进行轮循,那数据库的压力就更大了。

那么在这个时间,就需要一套能支持发布-订阅模式的分布式消息总线,那这个问题就可以很好的解决了,比如采用一些成熟的消息总线进行实现,比如MSMQ或者采用比如开源的NServiceBus的发布订阅机制就可以实现处理这种需求,其系统结构就会变成如下所示:

本分布式消息总线,目前广泛的被应用于分布式缓存的更新通知,当在N百台客户短在使用缓存的过程之中,某个操作修改了缓存的数据,必须会导致其他终端缓存的失效,那么使用基于Socket的分布式消息总线之后,我们可以做了修改了即可实时通知,做到缓存数据保持最新,再比如医疗应用之中的危急值管理,当发现检验、检查危急值之后,需要及时通知病区启动声光报警系统等,提醒医护工作人员及相关领导做出相应的措施,再比如应用于异构系统整合,当检验系统做出检验报告,通过消息总线进行发布,HIS系统则即时会收到检验报告数据而实现系统的整合。

二、基于Socket的实现

目前能够实现发布订阅模式的开源产品非常之多,为什么还要制造轮子呢,其主要原因有以下几点

1)像NServiceBus这种东西基于MSMQ,在大量的发布者-订阅者的情况下性能不佳。

2)此类东西太过于庞大、不易使用和配置。

3)学习成本过高。

那为什么要使用Socket技术进行实现呢,其主要原因是有以下几点:

1)使用高效的Socket通信技术,高效、支持更多的客户端。

2)使用简单,不需要定义太多额外的东西,只需要定义主题和消息即可使用。

目前本发布订阅框架是基于AgileEAS.NET SOA中间件平台Socket框架实现的,有关于些Socket框架的技术细节请参考AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-下载配置AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-代码解析文章进行了解和学习。

目前本发布订阅框架并直接集成于AgileEAS.NET SOA Socket通信框架之中并且随其一并发布,下面简单介绍一下其API:

在本框架之中定义了一个消息总线接口IMessageBus:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.Collections;

   6:  

   7: namespace EAS.Messages

   8: {

   9:     /// <summary>

  10:     /// 消息总线接口定义。

  11:     /// </summary>

  12:     public interface IMessageBus : IDisposable

  13:     {

  14:         /// <summary>

  15:         /// 注册发布者。

  16:         /// </summary>

  17:         /// <param name="publisher">发布者。</param>

  18:         void AddPublisher(string publisher);

  19:  

  20:         /// <summary>

  21:         /// 注册发布者。

  22:         /// </summary>

  23:         /// <param name="publisher">发布者。</param>

  24:         /// <param name="topic">主题。</param>

  25:         void AddPublisher(string publisher, string topic);

  26:  

  27:         /// <summary>

  28:         /// 发布一条消息到总线。

  29:         /// </summary>

  30:         /// <param name="topic">主题。</param>

  31:         /// <param name="message">发布的消息。</param>

  32:         void Publish(string topic, object message);

  33:  

  34:         /// <summary>

  35:         /// 订阅消息。

  36:         /// </summary>

  37:         /// <param name="subscriber">订阅者。</param>

  38:         /// <param name="topic">主题。</param>

  39:         /// <param name="notifyHandler">订阅通知。</param>

  40:         void Subscribe(object subscriber, string topic, MessageNotifyHandler notifyHandler);

  41:  

  42:         /// <summary>

  43:         /// 订阅消息。

  44:         /// </summary>

  45:         /// <param name="subscriber">订阅者。</param>

  46:         /// <param name="friendName">订阅者名称,用于处理离线订阅。</param>

  47:         /// <param name="topic">主题。</param>

  48:         /// <param name="notifyHandler">订阅通知。</param>

  49:         void Subscribe(object subscriber,string friendName ,string topic, MessageNotifyHandler notifyHandler);

  50:  

  51:         /// <summary>

  52:         /// 订阅消息。

  53:         /// </summary>

  54:         /// <param name="subscriber">订阅者。</param>

  55:         /// <param name="friendName">订阅者名称,用于处理离线订阅。</param>

  56:         /// <param name="topic">主题。</param>

  57:         /// <param name="notifyHandler">订阅通知。</param>

  58:         /// <param name="changedHandler">发布者状态变化委托。</param>

  59:         void Subscribe(object subscriber, string friendName, string topic, MessageNotifyHandler notifyHandler,PublisherSstatusChangedHandler changedHandler);

  60:  

  61:         /// <summary>

  62:         /// 退订消息。

  63:         /// </summary>

  64:         /// <param name="subscriber">订阅者。</param>

  65:         void Unsubscribe(object subscriber);

  66:  

  67:         /// <summary>

  68:         /// 退订消息。

  69:         /// </summary>

  70:         /// <param name="subscriber">订阅者。</param>

  71:         /// <param name="topic">主题。</param>

  72:         void Unsubscribe(object subscriber, string topic);

  73:  

  74:         /// <summary>

  75:         /// 退订消息。

  76:         /// </summary>

  77:         /// <param name="subscriber">订阅者。</param>

  78:         /// <param name="friendName">订阅者名称,用于处理离线订阅。</param>

  79:         /// <param name="topic">主题。</param>

  80:         void Unsubscribe(object subscriber, string friendName, string topic);

  81:     }

  82: }

IMessageBus就基于Socket发布订阅消息总线的灵魂接口,也是基唯一的发布者调用者功能入口,也就是说不管你是发布者还是订阅者都需要调用这个接口,如果你是发布者请调用IMessageBus接口的Publish方法向消息总线发布消息,如果是你订阅者请通过IMessageBus的订阅方法进行订阅,当你订阅了某个主题之后,有发布者发布该主题的消息,你即可以收到消息并调用订阅回调函数进行处理。

三、实现一个简单的例子

现在我们开始一个简单的应用消息总线的例子,本例子代码解决方案由下图4个项目组成:

其中:Demo.Messages项目定义发布者、订阅者所使用的消息对象和消息主题。

Demo.Publisher项目为发布者代码。

Demo.Subscriber项目为订阅者代码。

Demo.Server项目为服务端代码。

在Demo.Messages项目之中,我们定义了一个消息Message:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.Xml.Serialization;

   6:  

   7: namespace Demo.Messages

   8: {

   9:     [Serializable]

  10:     public class Message

  11:     {

  12:         [XmlElement]

  13:         public Guid ID

  14:         {

  15:             get;

  16:             set;

  17:         }

  18:     }

  19: }

消息Message很简单,只有一个属性ID,同时 还需要定义一个消息主题:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5:  

   6: namespace Demo.Messages

   7: {

   8:     public class Topics

   9:     {

  10:         public static readonly string DEMO_TOPIC = "演示消息";

  11:     }

  12: }

我们定义了一个消息主题为“演示消息”。

在Demo.Publisher项目之中,没有太多额外的代码,只有在Program.cs写了以下简单的调用代码:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using EAS.Messages;

   6:  

   7: namespace Demo.Publisher

   8: {

   9:     class Program

  10:     {

  11:         static void Main(string[] args)

  12:         {

  13:             var container = EAS.Objects.ContainerBuilder.BuilderDefault();

  14:             var bus = container.GetComponentInstance("MessageBus") as IMessageBus;

  15:             System.Console.WriteLine("Publisher");

  16:  

  17:             while (System.Console.ReadLine()!="exit")

  18:             {

  19:                 var m = new Messages.Message { ID = Guid.NewGuid() };

  20:                 bus.Publish(Demo.Messages.Topics.DEMO_TOPIC, m);

  21:                 System.Console.WriteLine(string.Format("Publish:{0}", m.ID));

  22:             }

  23:         }

  24:     }

  25: }

从IOC容器获取一个消息总线IMessageBus对象,并调用Publish函数发布消息”bus.Publish(Demo.Messages.Topics.DEMO_TOPIC, m);“。

当然了,使用了IOC容器,就离来开配置文件了,其App.config文件内容如下:

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <configuration>

   3:   <configSections>

   4:     <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" />

   5:   </configSections>

   6:   <eas>

   7:     <objects>

   8:       <!--消息总线-->

   9:       <object name="MessageBus" assembly="EAS.MicroKernel" type="EAS.Sockets.Bus.SocketBus" LifestyleType="Singleton">

  10:         <property name="Url" type="string" value="socket.tcp://127.0.0.1:6606/"/>

  11:       </object>

  12:     </objects>

  13:   </eas>

  14: </configuration>

在Demo.Subscriber项目之中,使用与Demo.Publisher一模一样的配置文件,其Program.cs代码如下:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using EAS.Messages;

   6:  

   7: namespace Demo.Subscriber

   8: {

   9:     class Program

  10:     {

  11:         static void Main(string[] args)

  12:         {

  13:             var container = EAS.Objects.ContainerBuilder.BuilderDefault();

  14:             var bus = container.GetComponentInstance("MessageBus") as IMessageBus;

  15:             System.Console.WriteLine("Subscriber");

  16:  

  17:             bus.Subscribe(new Program(), "Subscriber1", Demo.Messages.Topics.DEMO_TOPIC, MessageNotify);

  18:             System.Console.ReadLine();

  19:         }

  20:  

  21:         static void MessageNotify(object m)

  22:         {

  23:             Demo.Messages.Message message = m as Demo.Messages.Message;

  24:             System.Console.WriteLine(string.Format("Subscribe:{0}", message.ID));

  25:         }

  26:     }

  27: }

其中代码bus.Subscribe(new Program(), "Subscriber1", Demo.Messages.Topics.DEMO_TOPIC, MessageNotify);:完成把消息订阅到MessageNotify通知函数之中。

在Demo.Server项目之中,启动服务器并且开始接收订阅和发布:

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using EAS.Sockets;

   6:  

   7: namespace Demo.Server

   8: {

   9:     class Program

  10:     {

  11:         static void Main(string[] args)

  12:         {

  13:             SocketServer socketServer = new SocketServer(128);

  14:             socketServer.Port = 6606;

  15:             socketServer.Logger = new EAS.Loggers.ConsoleLogger(); 

  16:             socketServer.Initialize();

  17:             System.Console.WriteLine("Server Starting...");

  18:             socketServer.StartServer();

  19:             System.Console.WriteLine("Server Startup!");

  20:             System.Console.ReadLine();

  21:         }

  22:     }

  23: }

到此为止,所有代码均已完成,是不是很简单,接下来,我们跑起来验证一下效果。

四、验证效果

我们在编译输入目录Publish下先启动Demo.Server.exe,再启动两个Demo.Subscriber.exe,再启动一个Demo.Publisher.exe,在Demo.Publisher.exe控制台按回车键:

OK,搞定。

五、源代码下载

本程序的源代码已上传到服务器,请通过http://112.74.65.50/downloads/eas/Demo.Pub_Sub.rar进行下载,如果在开发过程之中想要了解更多有关Socket通信框架以及更多AgileEAS.NET SOA中间件平台的技术资源,请通过AgileEAS.NET SOA 网站:http://www.smarteas.net最新下载栏目进行下载。

六、问题反馈

麻烦大家在通过视频进行学习的时候能及时把问题反馈给楼主,或者有什么需要改进的一些建议都请向楼主直接反馈,以下是联系方式:

团队网站:http://www.agilelab.cn

AgileEAS.NET网站:http://www.agileeas.net

官方博客:http://eastjade.cnblogs.com

github:https://github.com/agilelab/eas

QQ群:113723486(AgileEAS SOA 平台)/上限1000人

199463175(AgileEAS SOA 交流)/上限1000人

120661978(AgileEAS.NET 平台交流)/上限1000人

邮件:james@agilelab.cn,mail.james@qq.com,

电话:18629261335。

分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载的更多相关文章

  1. 分布式消息总线,基于.NET Socket Tcp的发布-订阅框架之离线支持,附代码下载

    一.分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.N ...

  2. 基于.NET Socket Tcp的发布-订阅框架

    基于.NET Socket Tcp的发布-订阅框架 一.分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时.高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已 ...

  3. 分享一个以前写的基于C#语言操作数据库的小框架

    一:前言 这个是以前写的操作MySQL数据库的小型框架,如果是中小型项目用起来也是很不错的,里面提供Filter.ModelPart.Relationship等机制实现操作数据库时的SQL语句的拼接和 ...

  4. kafka:一个分布式消息系统

    1.背景 最近因为工作需要,调研了追求高吞吐的轻量级消息系统Kafka,打算替换掉线上运行的ActiveMQ,主要是因为明年的预算日流量有十亿,而ActiveMQ的分布式实现的很奇怪,所以希望找一个适 ...

  5. Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua

    开心一刻 我找了个女朋友,挺丑的那一种,她也知道自己丑,平常都不好意思和我一块出门 昨晚,我带她逛超市,听到有两个人在我们背后小声嘀咕:"看咱前面,想不到这么丑都有人要." 女朋友 ...

  6. 分享一个自己写的基于TP的关系模型(四)

    修复分页BUG,原有代码查询到最后一页就一只查询最后一页 $ ? $; $this->maxPage = ceil($this->total/$this->rows); //$thi ...

  7. 分享一个自己写的基于TP的关系模型(三)

    这段时间对模型做了升级和优化,并将版本更新到TP3.2. 下载 下载后请将目录放置TP的Library目录下 1.数据节点优化,原来的节点为模型的名称或者表名,现在更新为定义关系的方法名 public ...

  8. 分享一个自己写的基于TP的关系模型(2)

    1.增加多对多关系的处理 /** * 定义关系 * @return array */ public function test4(){ //参数说明 //关联的模型 //主表关联字段 //关联中间表 ...

  9. 分享一个自己写的基于TP的关系模型

    为了说明问题,假设现在有表test1,test1有从表test2:test1属于test3,test1和test4多对多,关联表test1_test4. 1.定义关系 class Test1Model ...

随机推荐

  1. thinkphp3.2.3版本文件目录及作用

    下载thinkphp3.2.3版本,解压缩后将文件夹名字改为thinkphp,然后放在www目录下,里面的文件夹和文件的名字和作用如下:(前面有Tab健的表示下一级,thinkphp是根目录) //t ...

  2. CMake

    使用CMake编译跨平台静态库 http://www.tuicool.com/articles/3uu2Yj cmake命令 安装.用法简介 https://fukun.org/archives/04 ...

  3. Python

    语法 #!/usr/bin/python 注释:# 编码:# -*- coding: UTF-8 -*- 缩进 运算符 算数运算符 + 加 - 两个对象相加 a + b 输出结果 30 - 减 - 得 ...

  4. 行为驱动开发iOS <收藏>

    前段时间在design+code购买了一个学习iOS设计和编码在线课程,使用Sketch设计App,然后使用Swift语言实现Designer News客户端.作者Meng To已经开源到Github ...

  5. 推荐几款我一直在用的chrome插件(上)

    我用的chrome插件挺多的,所谓工欲善其事必先利其器,我热衷于搜寻好用的工具来让我平时的工作事半功倍.下面介绍几款我正在用的感觉还不错的插件,如果大家还有其它好用的(肯定有,chrome插件库太庞大 ...

  6. Find and delete duplicate files

    作用:查找指定目录(一个或多个)及子目录下的所有重复文件,分组列出,并可手动选择或自动随机删除多余重复文件,每组重复文件仅保留一份.(支持文件名有空格,例如:"file  name" ...

  7. C(C++)/ 数据结构 链表

    内容概括: 一.链表简介及创建列表 二.添加节点 三.链表排序 代码编译平台: CentOS 6.4 64b 一.链表简介及创建列表: 传统数组缺点: 传统数组长度需要事先设定,不能改变,内存由系统自 ...

  8. 常用linux 命令 -字符串相关

    参考网络文章,个人工作总结 题记:一般对字符串的操作有以下几种:求长度,截取字符串,拼接字符串,找字符串中某个字符的索引 1 expr 命令 1.1 定义 man 手册 Print the value ...

  9. iptables过滤设置服务端口

    1.为SSH跟换连接端口 修改SSH配置文件:/etc/ssh/sshd_config #找到Port 22,这里是标识默认使用22端口,修改为想要的端口. Port Port 2.查看iptable ...

  10. 【GitHub Desktop】MacOS和Win下配置及简单的使用

    一. GitHub介绍 1.GitHub 是为开发者提供 Git 仓库的托管服务.这是一个让开发者与朋友.同事.同学及陌生人共享代码的完美场所. 总结一下,GitHub 最大的特征是"面向人 ...