工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析

时间:2023-02-26 15:33:26

1.[连载]《C#通讯(串口和网络)框架的设计与实现》

2.[开源]C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍

2.应用SuperIO(SIO)和开源跨平台物联网框架ServerSuperIO(SSIO)构建系统的整体方案

3.C#工业物联网和集成系统解决方案的技术路线(数据源、数据采集、数据上传与接收、ActiveMQ、Mongodb、WebApi、手机App)

5.ServerSuperIO开源地址:https://github.com/wxzz/ServerSuperIO

目       录

工业物联网或系统集成中应用消息队列(ActiveMQ)的场景全面分析... 1

前言... 1

第一章           终端/交互场景... 3

1.1           终端设备... 3

1.2           通讯机制... 3

第二章           ActvieMQ应用场景... 4

2.1           发布/订阅(Publish/Subscribe)... 4

2.2           生产者/消费者(Producer/Consumer)... 7

2.3           请求/应答(Request/Response)... 10

第三章           假定场景分析... 16

3.1           通讯层... 16

3.2           数据业务层... 16

3.3           综述... 16

前言

互联网技术已经发展的很成熟了,各种开源的代码、框架和解决方案等。鉴于互联网技术的通用性,势必向其他领域延展。不管是工业4.0,还是互联网+  工业,互联网技术向工业领域传导也是必然的。

所以,对于工业方面的应用场景的技术储备和技术线路调研也是日常工作很重要的一部分,为公司的横向和纵向发展提供技术平台和保障,当然也取决于领导的视野。

第一章     终端/交互场景

任何技术都是为业务服务,而业务是有特定的应用场景。离开了实现环境去谈技术是没有实际意义的,解决实际问题而又能保证相当长时间内的稳定性是我们努力实现的目标。同时要从多个角度来考虑问题,以及做出平衡。

1.1    终端设备

(1)    终端种类:嵌入式硬件/传感器、PC机(监测站、大型监控设备等)、手机终端等。

(2)    交互方式:单向交互,数据上传,可能服务端会有返回确认信息,证明数据已经收到了;双向交互,服务端不仅仅会返回确认信息,同时还要主动下发给指定终端命令信息,例如:控制硬件设备机械动作命令、修改硬件设备参数命令、以及补传相关数据信息命令等等。

(3)    设备管理:这里指的设备管理是说设备的状态,包括两个方面:设备IO状态和设备通讯状态。设备IO状态包括:IO打开和IO关闭。设备通讯状态包括:通讯中断、通讯干扰和通讯正常。为了判断故障,这里的逻辑关系是:IO打开的时候不一定代表通讯正常;IO关闭不一定代表通讯中断;通讯中断不一定代表IO关闭;通讯干扰不一定代表IO打开。

(4)    数据完整性:允许数据缺失,一般在原来数据基础上的增量数据是可以允许丢失的;不允许数据缺失,一般脉冲数据是不允许数据丢失的。

1.2    通讯机制

(1)主动请求数据:服务器端主动下发命令给终端,让谁上传数据、上传什么数据都由服务器端决定。

(2)被动接收数据:服务器端被动接收终端上传的数据,根据数据信息进行数据处理,以及返回确认信息。

第二章     ActvieMQ应用场景

消息队列比较多,本文以ActiveMQ为例进行介绍,全部代码实现C#为主,主要考虑到常见的应用模式。事例代码下载:http://pan.baidu.com/s/1qXZ1sU4

2.1    发布/订阅(Publish/Subscribe)

一个信息发布者在某一个主题上发布消息,所有订阅该主题的订阅都会收到相同的消息,这种模式是一对多的关系,如下图:

工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析

发布端代码:

static void Main(string[] args)
{
try
{
IConnectionFactory factory = new ConnectionFactory("tcp://localhost:61616/");
using (IConnection connection = factory.CreateConnection())
{
using (ISession session = connection.CreateSession())
{
IMessageProducer prod = session.CreateProducer(new Apache.NMS.ActiveMQ.Commands.ActiveMQTopic("Topic")); string text = Console.ReadLine();
while (text!="exit")
{
ITextMessage msg = prod.CreateTextMessage();
msg.Text = text;
prod.Send(msg, Apache.NMS.MsgDeliveryMode.NonPersistent, Apache.NMS.MsgPriority.Normal, TimeSpan.MinValue);
Console.WriteLine("Sending: " + text);
System.Threading.Thread.Sleep(2000);
}
}
}
Console.ReadLine();
}
catch (System.Exception e)
{
Console.WriteLine("{0}", e.Message);
Console.ReadLine();
}
}

 订阅端代码:

static void Main(string[] args)
{
try
{
IConnectionFactory factory = new ConnectionFactory("tcp://localhost:61616/");
using (IConnection connection = factory.CreateConnection())
{
connection.ClientId = "testing listener1";
connection.Start(); using (ISession session = connection.CreateSession())
{
IMessageConsumer consumer = session.CreateDurableConsumer(new Apache.NMS.ActiveMQ.Commands.ActiveMQTopic("Topic"), "testing listener1", null, false);
consumer.Listener += new MessageListener(consumer_Listener);
Console.ReadLine();
}
connection.Stop();
connection.Close();
}
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
} static void consumer_Listener(IMessage message)
{
try
{
ITextMessage msg = (ITextMessage)message;
Console.WriteLine("Receive: " + msg.Text);
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
}
}

2.2    生产者/消费者(Producer/Consumer)

生产者生产了一块香皂,消费者购买了该块香皂,使用完了,就在这个世界上消息了,生产者和消费者之间的关系存在一种偶然性,这是一对一的关系,如下图:

工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析

生产端代码:

 static void Main(string[] args)
{
try
{
IConnectionFactory factory = new ConnectionFactory("tcp://localhost:61616/");
using (IConnection connection = factory.CreateConnection())
{
using (ISession session = connection.CreateSession())
{
IMessageProducer prod = session.CreateProducer(new Apache.NMS.ActiveMQ.Commands.ActiveMQQueue("Queue")); string text = Console.ReadLine();
while (text != "exit")
{
ITextMessage msg = prod.CreateTextMessage();
msg.Text = text;
prod.Send(msg, Apache.NMS.MsgDeliveryMode.NonPersistent, Apache.NMS.MsgPriority.Normal, TimeSpan.MinValue);
Console.WriteLine("Sending: " + text);
System.Threading.Thread.Sleep(2000);
}
}
}
Console.ReadLine();
}
catch (System.Exception e)
{
Console.WriteLine("{0}", e.Message);
Console.ReadLine();
}
}

消费端代码:

static void Main(string[] args)
{
try
{
IConnectionFactory factory = new ConnectionFactory("tcp://localhost:61616/");
using (IConnection connection = factory.CreateConnection())
{
//connection.ClientId = "testing listener2";
connection.Start();
using (ISession session = connection.CreateSession())
{
IMessageConsumer consumer = session.CreateConsumer(new Apache.NMS.ActiveMQ.Commands.ActiveMQQueue("Queue"));
consumer.Listener += new MessageListener(consumer_Listener);
Console.ReadLine();
}
connection.Stop();
connection.Close();
}
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
} static void consumer_Listener(IMessage message)
{
try
{
ITextMessage msg = (ITextMessage)message;
Console.WriteLine("Receive: " + msg.Text);
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
}
}

2.3    请求/应答(Request/Response)

请求-应答的通信方式应用很普遍,客户端向服务端上传实时数据或参数,服务端处理完之后,要返回确认信息,这种交互关系如下图:

工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析

客户端代码:

static void Main(string[] args)
{
IConnectionFactory factory = new ConnectionFactory("tcp://localhost:61616/");
try
{
using (IConnection connection = factory.CreateConnection())
{
connection.Start();
using (ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge))
{
IDestination destination = new Apache.NMS.ActiveMQ.Commands.ActiveMQQueue("client.messages"); IMessageProducer producer = session.CreateProducer(destination);
producer.DeliveryMode=MsgDeliveryMode.NonPersistent; IDestination tempDest = session.CreateTemporaryQueue();
IMessageConsumer responseConsumer = session.CreateConsumer(tempDest);
responseConsumer.Listener += new MessageListener(consumer_Listener); string text = Console.ReadLine();
while (text != "exit")
{
ITextMessage msg = session.CreateTextMessage();
msg.Text = text;
msg.NMSReplyTo = tempDest;
msg.NMSCorrelationID = DateTime.Now.ToString("yyyyMMddHHmmss");
producer.Send(msg, Apache.NMS.MsgDeliveryMode.NonPersistent, Apache.NMS.MsgPriority.Normal, TimeSpan.MinValue);
Console.WriteLine("Sending: " + text);
System.Threading.Thread.Sleep(2000);
} Console.ReadLine();
}
connection.Stop();
connection.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
} static void consumer_Listener(IMessage message)
{
try
{
ITextMessage msg = (ITextMessage)message;
Console.WriteLine("Receive: " + msg.Text);
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
}
}

服务端代码:

 private static ISession session;

        private static IMessageProducer replyProducer;
static void Main(string[] args)
{
IConnectionFactory factory = new ConnectionFactory("tcp://localhost:61616/");
try
{
IConnection connection = factory.CreateConnection();
connection.Start();
session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge); IDestination adminQueue = new Apache.NMS.ActiveMQ.Commands.ActiveMQQueue("client.messages");
replyProducer = session.CreateProducer();
replyProducer.DeliveryMode=MsgDeliveryMode.NonPersistent; IMessageConsumer consumer = session.CreateConsumer(adminQueue);
consumer.Listener += new MessageListener(consumer_Listener);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
} static void consumer_Listener(IMessage message)
{
try
{
ITextMessage response = session.CreateTextMessage();
if (message is ITextMessage) {
ITextMessage txtMsg = (ITextMessage)message;
string messageText = txtMsg.Text;
response.Text = messageText; Console.WriteLine("Receive:" + messageText);
} response.NMSCorrelationID=message.NMSCorrelationID; replyProducer.Send(message.NMSReplyTo, response);
}
catch (Exception e)
{
Console.WriteLine(e.Message); }
}

第三章     假定场景分析

我们以系统建设过程中的构架来分析消息队列在两个层面的问题,通讯层和数据业务层。

3.1    通讯层

通讯层是否可以用消息队列(ActiveMQ)?这个问题取决于两方面:1、如果终端设备有嵌入式硬件,甚至还是C51开发的,那么在系统集成和物联的过程中,就涉及到兼容性的问题。显然和消息队列进行对接是一件头痛的事,用C51写一个对接的驱动不是不可能,但是要评估工作量和稳定性。2、服务端与指定某个终端双向交互频繁的情况,特别是服务端实时发送设备校准命令的情况,这种情况消息队列是不如通讯框架的。

3.2    数据业务层

服务端接收到数据后,完全可以使用消息队列的生产者和消费者模式处理数据,对系统的业务进行解耦。

下发命令也可以通过消息队列,这样可以统一控制端的接口,再由通讯框架下发到指定的终端。

3.3    综述

综合考虑,建议在通讯层使用通讯框架,对于设备的IO状态和通讯状态能够及时反应,通讯效率也是能够得到保障的;对于数据业务层,建议不要放在通讯框架内部进行处理,可以使用消息队列,配合通讯框架使用。

整体架构图如下:

工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析

文章得到了群友支持:

工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析

工业物联网或系统集成中应用消息队列(ActiveMQ,C#的demo)的场景全面分析的更多相关文章

  1. C#中使用消息队列RabbitMQ

    在C#中使用消息队列RabbitMQ 2014-10-27 14:41 by qy1141, 745 阅读, 2 评论, 收藏, 编辑 1.什么是RabbitMQ.详见 http://www.rabb ...

  2. Handler机制中的消息队列

    --> 学习自蘑菇街大佬 Handler机制可以看成是一个消息阻塞队列,当有消息时立即处理消息,没有消息时则阻塞.在Android系统中APP启动后很快进入死循环,不断读取MessageQueu ...

  3. GaussDB(DWS)*享消息队列实现的三大功能

    摘要:本文将详细介绍GaussDB(DWS)*享消息队列的实现. 本文分享自华为云社区<GaussDB(DWS)CBB组件之共享消息队列介绍>,作者:疯狂朔朔. 1)共享消息队列是什么? ...

  4. 第十一章 企业项目开发--消息队列activemq

    注意:本章代码基于 第十章 企业项目开发--分布式缓存Redis(2) 代码的github地址:https://github.com/zhaojigang/ssmm0 消息队列是分布式系统中实现RPC ...

  5. 消息队列ActiveMQ的使用详解

    通过上一篇文章 <消息队列深入解析>,我们已经消息队列是什么.使用消息队列的好处以及常见消息队列的简单介绍. 这一篇文章,主要带大家详细了解一下消息队列ActiveMQ的使用. 学习消息队 ...

  6. 消息队列 ActiveMQ 、RocketMQ 、RabbitMQ 和 Kafka 如何选择?

    「 预计阅读 6 分钟 」 旁白:这是一篇拖更了N久的文章...0.0(看不见我~) 往期回顾 前端框架 jQuery 和 Vue 如何选择? 安全框架 Shiro 和 Spring Security ...

  7. 在C&num;中使用消息队列RabbitMQ

    1.什么是RabbitMQ.详见 http://www.rabbitmq.com/. 作用就是提高系统的并发性,将一些不需要及时响应客户端且占用较多资源的操作,放入队列,再由另外一个线程,去异步处理这 ...

  8. 如何应用&period;NET中的消息队列服务

    建立一个队列是应用MSMQ的第一步.您可以通过Windows计算机管理控制台中的消息队列选项完成这一操作,或者自己编程建立一个队列.列表A中的C#代码建立了一个新的私有MSMQ消息队列(如果不存在队列 ...

  9. 在WCF中使用消息队列

    在一些大型的解决方案中,假设我们的服务没有办法一直在线,或者因为这样那样的原因宕机了,有没有什么办法让客户端的影响最小化呢?答案是可以通过消息队列的方式,哪怕服务是没有在线的,客户端依然可以继续操作. ...

随机推荐

  1. java Byte&lbrack;&rsqb; to String&lpar;hex&rpar;

    1. 字节数组转换成16进制字符展示 2.代码 package com.goodfan; public class ByteArrayToString { private static char[] ...

  2. from collections import OrderedDict

    在python中,dict这个数据结构由于hash的特性,是无序的,这在有时候会给我们带来一些麻烦,幸运的是, collections模块为我们提供了OrderdDict,当你要获取一个有序的字典对象 ...

  3. 0007《SQL必知必会》笔记03-汇总与分组数据

    1.有些时候需要数据的汇总值,而不是数据本身,比如对某些数据求和.计数.求最大最小值.求平均值,因此就有了5个聚集函数:AVE().COUNT().MAX().MIN().SUM(): (1)求平均值 ...

  4. 新浪微博客户端&lpar;36&rpar;-自定义带placeholder的TextView

    iOS 上自带的UITextView竟然不能设置placeholder,但是UITextView却可以,我也真是醉了.没办法了,自己写一个 DJTextView.h #import <UIKit ...

  5. Ant 随想

    Ant是一种基于Java的build工具 面向任务构建,属性与于shell脚本中命令功能类型. <?xml version="1.0"?> <project na ...

  6. Visual Studio 2015 Professional 破解

    Visual Studio 2015 Professional 版本 破解序列号:HMGNV-WCYXV-X7G9W-YCX63-B98R2

  7. Java课程设计——计算数学表达式的程序(201521123051 谢庆圆)

    计算数学表达式的程序(201521123051 谢庆圆) 1.团队课程设计博客链接 团队课程设计博客链接 2.个人负责模块或任务说明 1.计算数字表达式中操作按钮的实现(右容器) 2.. 注册监听器以 ...

  8. Hashtable源码解析

    Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. Hashtable也是JDK1.0引入的 ...

  9. UOJ&num;75&period; 【UR &num;6】智商锁 随机化算法 矩阵树定理

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ75.html 前言 根本没想到. 题解 首先我们可以考虑一种做法: 找一些图,使得他们各自的生成树个数乘起来等于 k. 那 ...

  10. caffe-win10-cifar10另

    上一篇主要以bat形式实现了leveldb形式的cifar10,因为对于shell脚本不甚熟悉,所以这次专门利用.sh调用来实现lmdb形式的cifar10. 1.下载数据 同上一篇. 2.数据转换和 ...