第一部分引用于:点击打开

1:简单介绍

PUB-SUB模式一般处理的都不是系统的关键数据。发布者不关注订阅者是否收到发布的消息,订阅者也不知道自己是否收到了发布者发出的所有消息。你也不知道订阅者何时开始收到消息。类似于广播,收音机。因此逻辑上,它都不是可靠的。这个可以通过与请求响应模型组合来解决。


图1:简单的发布订阅模式


图2:与请求响应模式组合的发布订阅模式

2:案例

定义IPublishser接口

namespace NetMQDemoPublisher
{
public interface IPublisher:IDisposable
{
/// <summary>
/// 发布消息
/// </summary>
/// <param name="topicName">主题</param>
/// <param name="data">内容</param>
void Publish(string topicName, string data);
}
}

Publisher实现类

namespace NetMQDemoPublisher
{
public class Publisher:IPublisher
{
private object _lockObject = new object(); private PublisherSocket _publisherSocket; public Publisher(string endPoint)
{
_publisherSocket = new PublisherSocket();
_publisherSocket.Options.SendHighWatermark = ;
_publisherSocket.Bind(endPoint);
}
#region Implementation of IDisposable /// <summary>
/// 执行与释放或重置非托管资源相关的应用程序定义的任务。
/// </summary>
public void Dispose()
{
lock (_lockObject)
{
_publisherSocket.Close();
_publisherSocket.Dispose();
}
} /// <summary>
/// 发布消息
/// </summary>
/// <param name="topicName">主题</param>
/// <param name="data">内容</param>
public void Publish(string topicName, string data)
{
lock (_lockObject)
{
_publisherSocket.SendMoreFrame(topicName).SendFrame(data);
}
} #endregion
}
}

Publisher窗口界面

界面中实现的功能代码

namespace NetMQDemoPublisher
{
public partial class PublisherForm : Form
{
private IPublisher publisher;
public PublisherForm()
{
InitializeComponent();
publisher = new Publisher("tcp://127.0.0.1:8888");
} private void button1_Click(object sender, EventArgs e)
{
string strContent = textBox1.Text;
ListViewItem item = new ListViewItem(string.Format("topic:NetMQ,Data:{0}", strContent));
listView1.Items.Add(item);
publisher.Publish("NetMQ", strContent);
}
}
}

定义ISubscriber接口

namespace NetMQDemoSubscriber
{
public interface ISubscriber:IDisposable
{
/// <summary>
/// 事件
/// </summary>
event Action<string, string> Nofity; /// <summary>
/// 注册订阅主题
/// </summary>
/// <param name="topics"></param>
void RegisterSubscriber(List<string> topics); /// <summary>
/// 注册订阅
/// </summary>
void RegisterSbuscriberAll(); /// <summary>
/// 移除所有订阅消息,并关闭
/// </summary>
void RemoveSbuscriberAll();
}
}

Subscriber实现类

namespace NetMQDemoSubscriber
{
public class Subscriber:ISubscriber
{
private SubscriberSocket _subscriberSocket = null;
private string _endpoint = @"tcp://127.0.0.1:9876"; public Subscriber(string endPoint)
{
_subscriberSocket = new SubscriberSocket();
_endpoint = endPoint;
}
#region Implementation of IDisposable /// <summary>
/// 执行与释放或重置非托管资源相关的应用程序定义的任务。
/// </summary>
public void Dispose()
{
throw new NotImplementedException();
} #endregion #region Implementation of ISubscriber public event Action<string, string> Nofity = delegate { }; /// <summary>
/// 注册订阅主题
/// </summary>
/// <param name="topics"></param>
public void RegisterSubscriber(List<string> topics)
{
InnerRegisterSubscriber(topics);
} /// <summary>
/// 注册订阅
/// </summary>
public void RegisterSbuscriberAll()
{
InnerRegisterSubscriber();
} /// <summary>
/// 移除所有订阅消息,并关闭
/// </summary>
public void RemoveSbuscriberAll()
{
InnerStop();
} #endregion #region 内部实现 /// <summary>
/// 注册订阅消息
/// </summary>
/// <param name="topics">订阅的主题</param>
private void InnerRegisterSubscriber(List<string> topics = null)
{
InnerStop();
_subscriberSocket = new SubscriberSocket();
_subscriberSocket.Options.ReceiveHighWatermark = ;
_subscriberSocket.Connect(_endpoint);
if (null == topics)
{
_subscriberSocket.SubscribeToAnyTopic();
}
else
{
topics.ForEach(item => _subscriberSocket.Subscribe(item));
}
Task.Factory.StartNew(() =>
{
while (true)
{
string messageTopicReceived = _subscriberSocket.ReceiveFrameString();
string messageReceived = _subscriberSocket.ReceiveFrameString();
Nofity(messageTopicReceived, messageReceived);
}
});
} /// <summary>
/// 关闭订阅
/// </summary>
private void InnerStop()
{
_subscriberSocket.Close();
} #endregion
}
}

Subscriber窗口界面

窗体功能代码

namespace NetMQDemoSubscriber
{
public partial class SubscriberForm : Form
{
private ISubscriber subscriber;
public SubscriberForm()
{
InitializeComponent();
} private void SubscriberForm_Load(object sender, EventArgs e)
{
subscriber = new Subscriber("tcp://127.0.0.1:8888");
subscriber.RegisterSbuscriberAll();
subscriber.Nofity+= delegate(string s, string s1)
{
ListViewItem item = new ListViewItem(string.Format("topic:{0},Data:{1}", s, s1));
listView1.Items.Add(item);
};
}
}
}

运行后,Publiser开启一个,Subscirber开启三个,进行测试如图

源码下载

如果觉得文章好,记得关注一下公众号哟!

NetMQ 发布订阅模式 Publisher-Subscriber的更多相关文章

  1. NetMQ(三): 发布订阅模式 Publisher-Subscriber

    ZeroMQ系列 之NetMQ 一:zeromq简介 二:NetMQ 请求响应模式 Request-Reply 三:NetMQ 发布订阅模式 Publisher-Subscriber 四:NetMQ ...

  2. java 多线程 发布订阅模式:发布者java.util.concurrent.SubmissionPublisher;订阅者java.util.concurrent.Flow.Subscriber

    1,什么是发布订阅模式? 在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者).而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话 ...

  3. NetMQ发布订阅C#示例

    NetMQ (ZeroMQ to .Net),ØMQ号称史上最快中间件.它对socket通信进行了封装,使得我们不需要写socket函数调用就能完成复杂的网络通信.和一般意义上的消息队列产品不同的是, ...

  4. redis的发布订阅模式pubsub

    前言 redis支持发布订阅模式,在这个实现中,发送者(发送信息的客户端)不是将信息直接发送给特定的接收者(接收信息的客户端),而是将信息发送给频道(channel),然后由频道将信息转发给所有对这个 ...

  5. 观察者模式 vs 发布-订阅模式

    我曾经在面试中被问道,_“观察者模式和发布订阅模式的有什么区别?” _我迅速回忆起“Head First设计模式”那本书: 发布 + 订阅 = 观察者模式 “我知道了,我知道了,别想骗我” 我微笑着回 ...

  6. js设计模式之发布/订阅模式模式

    一.前言 发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知. 就和用户 ...

  7. js设计模式-发布/订阅模式

    一.前言 发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知. 就和用户 ...

  8. js之观察者模式和发布订阅模式区别

    观察者模式(Observer) 观察者模式指的是一个对象(Subject)维持一系列依赖于它的对象(Observer),当有关状态发生变更时 Subject 对象则通知一系列 Observer 对象进 ...

  9. 观察者模式Vs发布订阅模式

    1)观察者模式 观察者模式通俗的讲就是我们平事件调用(click/change等等) 大家先看这个图片.我们被观察者Subject(监听某个事件)发生改变时,观察者Observer监听到没改变做出调整 ...

随机推荐

  1. HttpWebRequest 高效并发问题

    默认请求连接数 是2,在服务器操作系统上默认为10. 如果不修改这个并发连接限制,那么客户端同时可以建立的 http 连接数就只有2个或10个. System.Net.ServicePointMana ...

  2. 主机性能监控之wmi 获取进程信息

    标 题: 主机性能监控之wmi 获取进程信息作 者: itdef链 接: http://www.cnblogs.com/itdef/p/3990499.html 欢迎转帖 请保持文本完整并注明出处 仅 ...

  3. JS基础-数组的常用方法-冒泡排序

    1.数组  1.关联数组    以数字作为元素下标的数组,就是索引数组.    以字符串作为元素下标的数组,就是关联数组.  2.js的关联数组    ex:在php中       $array=[& ...

  4. 别人的Linux私房菜(6)文件权限与目录配置

    账号与一般身份用户存放在/etc/passwd文件中 个人密码存放在/etc/shadow文件中 Linux所有组名存放在/etc/group中 ls -al查看所有信息并显示权限等 文件权限的10字 ...

  5. javascript 取整,取余数 math方法

    1.丢弃小数部分,保留整数部分 parseInt() 函数可解析一个字符串,并返回一个整数. parseInt(string, radix) 参数 描述 string 必需.要被解析的字符串. rad ...

  6. ESP32作为接入点AP

    作为接入点的第一个任务是使用esp_wifi_set_mode()函数设置ESP32 函数并传递请求,作为接入点,可以把ESP32设置为AP或者APSTA,即 esp_wifi_set_mode(WI ...

  7. 基于dsp_builder的算法在FPGA上的实现(转自https://www.cnblogs.com/sunev/archive/2012/11/17/2774836.html)

    一.摘要 结合dsp_builder.matlab.modelsim和quartus ii等软件完成算法的FPGA实现. 二.实验平台 硬件平台:DIY_DE2 软件平台:quartus ii9.0 ...

  8. 「WC2018」州区划分(FWT)

    「WC2018」州区划分(FWT) 我去弄了一个升级版的博客主题,比以前好看多了.感谢 @Wider 不过我有阅读模式的话不知为何 \(\text{LATEX}\) 不能用,所以我就把这个功能删掉了. ...

  9. value,innerHTML,innerText之间的区别

    value:是DOM对象的属性.主要用于获取单标签的属性,(针对单标签): innerHEML:用于获取闭合双标签里面的内容,(可以识别标签): innerText:用于获取闭合单标签里面的内容,(不 ...

  10. 重磅:Spring Boot 2.0 正式发布!

    Spring Boot 2.0 正式发布! 2018/03/01最新消息,传得沸沸扬扬的Spring Boot 2.0 正式发布了. 小编去看了下Spring Boot的官网,正式版本已经释放出来了! ...