基于ActiveMQ构建物联网系统

背景

现今已进入如火如荼的物联网时代,万物互联,设备从信息化走向数字化时代。生活中随处可见物联网的产品的应用场景;智能家居、智慧物业、智慧园区、智慧城市等。

作为专业的技术工程师,我们需要了解行业发展,支持行业技术应用构建的核心技术,提升自己在技术全都核心竞争力。

本章将重点介绍基于开源软件,我们如何快速实现设备的联网。

准备阶段

结构图如下

image.png

搭建MQTT服务器

此处以ActiveMQ服务器为例进行介绍。前面章节我们已经介绍了ActiveMQ产品的安装,此处主要介绍如何查看ActiveMQ是否支持MQTT协议

进入到ActiveMQ安装目录,打开对应应用程序的conf文件夹,打开activemq.xml

image.png

打开ActiveMQ,注意看一下activemq.xml文件中红色部分是否有被注释掉

image.png

启动服务,通过命令进入到ActiveMQ的 bin目录,执行如下脚本,已启动ActiveMQ服务器

./activemq start

即可得到如下的打印信息,则启动正常

image.png

 

准备好MQTT客户端(mqttfx为代表的)

在上面章节我们已经安装了ActiveMQ软件,接下来我们安装MQTT客户端,主要用于模拟设备端连接到平台。客户端使用mqttfx

下载地址:http://mqttfx.jensd.de/index.php/download

# Mac OS 下载地址
curl http://www.jensd.de/apps/mqttfx/1.7.0/mqttfx-1.7.0-macos.dmg

下载后直接安装即可。

模拟设备连接

使用安装好的mqttfx工具模拟设备端的链接,先启动软件

image.png

设置服务器参数(参照如下指引设置,然后apply即可;说明:第3步,服务器默认用户名密码是 admin、admin)

image.png

如上图所示,主要4步

  1. 设置连接名称
  2. 设置服务器地址和端口以及客户端名称(默认端口1883,客户端名称暂时可以随机生成)
  3. 设置用户名密码(默认是admin/admin)
  4. 直接保存应用(Apply)

再回到主界面,点击链接connect按钮,链接服务器

image.png

如上图所示,操作步䠫6步,主要完成两个工作,1与服务器建立连接(1、2、3步),2发布一个主题并发布一条消息(4、5、6步)

是否与服务器连接成功,主要按上面数字3所指向的按钮是否变为绿色

注意:发布消息用到了ActiveMQ的虚拟主题特性。前面一定添加VirtualTopic

发布消息默认是QoS0,这个主要是消息服务质量等级,主要有3个等级,分别如下

  • level0: 最多一次传输
  • level1: 最少一次传输
  • level2: 只有一次传输

官方详细说明:http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#qos-flows

优秀博客推荐:https://www.jianshu.com/p/8b0291e8ee02

开发后端消息接收程序

从上面的客户端实例中我们可以看到,客户端建立MQTT连接之后,发布了VirtualTopic/SN00001/status 主题;在此可以通过编写后端Java程序,进行接收设备消息,这里可以通过通配符的方式进行消息的接收

实例1:直接通过一个消息订阅端进行消息消费

    /*
     * 监听和接收  队列消息 虚拟主题MQTT 端直接用VirtualTopic/status发送消息;后端用queue方式接收Consumer.A.VirtualTopic.status
     * VirtualTopic.status
     */
    @JmsListener(destination = "VirtualTopic.*.status",containerFactory="jmsListenerContainerQueue")
    public void readVirtualTopicStatus(ActiveMQMessage message) {
        System.out.println("接受到《设备状态 Status》:" + message);
    }

如上代码,通过Spring框架的@JmsListener注解,监听虚拟主题VirtualTopic.*.status消息,这是是通过模糊匹配的方式进行消息接收,即为所有的VirtualTopic.开头和.status结尾的主题消息都会被订阅。

实例2:通过动态启动多个客户端进行消息的分流订阅

/*
 * 监听和接收  队列消息
 */
@JmsListener(destination = "Consumer.A.VirtualTopic.*.status", containerFactory = "jmsListenerContainerQueue")
public void readVirtualTopicStatusA(Message message) {
    printMessage(message, "消费端A收到订阅消息:>>>>《设备状态 Status》:");
}

/*
 * 监听和接收  队列消息
 */
@JmsListener(destination = "Consumer.B.VirtualTopic.*.status", containerFactory = "jmsListenerContainerQueue")
public void readVirtualTopicStatusB(Message message) {
    printMessage(message, "B>>>>接受到《设备状态 Status》:");
}

/***
  * 打印消息对象
  * @param message
  * @param title
  */
private void printMessage(Message message, String title) {
    if (message instanceof TextMessage) {
        TextMessage tm = (TextMessage) message;
        try {
            System.out.println(title + tm.getText().toString());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    } else if (message instanceof ActiveMQBytesMessage) {
        ActiveMQBytesMessage bytesMessage = (ActiveMQBytesMessage) message;
        if (bytesMessage != null) {
            try {
                byte[] bt = new byte[(int) bytesMessage.getBodyLength()];
                bytesMessage.readBytes(bt);
                System.out.println(title + new String(bt));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 

如上代码,方法readVirtualTopicStatusA和readVirtualTopicStatusB都从消息队列Consumer.B.VirtualTopic.*.status中进行消息接收,并消费。在系统上我们可以通过程序动态启动多个这样的客户端,从而提升消息消费者个数,提高消息消费的速度。这也是ActiveMQ在高并发情况下提供的多端消费特性,从而实现消息的分流消费。在实际生产过程中非常重要。

实现消息的收发

一般是设备连接到平台之后,有消息发送必然后消息接收,消息接收一般主要解决通过平台端去控制设备做某事,比如通过平台去控制设备重启,升级固件等操作,即都需要下发相应的指令。

设备端要收到平台的指令,首先是设备端需要订阅与自己匹配的主题,在本案例中以设备的ID为关键码进行区分,因此每个设备都订阅一个自己在平台中独一无二的主题。比如上面客户端SN00001的设备,订阅的命令主题为: smartdevice/SN00001/command

image.png

服务器端选定设备并下发指令,单元测试代码如下

/***
     * 发送消息到Topic
     */
    @Test
    void sendMessageToTopic() {
        msgProducer.sendTopicMessage("smartdevice.SN00001.command",
                "Topic Message>>来自服务器端的消息:" + System.currentTimeMillis());
        System.out.println("发送Topic消息成功!");
    }

以上需要注意的点在于,设备订阅是smartdevice/SN00001/command;而在服务器端下发指令是smartdevice.SN00001.command主题(斜杠换成了点),这个与ActiveMQ内部的转换机制有关,按这个规范操作即可。

实际msgProducer的方法实现如下代码,比较简单

    @Autowired 
    private JmsMessagingTemplate jmsTemplate;
    /***
     * 向主题发送消息
     * @param topicName 主题名称
     * @param message 消息体
     */
    public void sendTopicMessage(String topicName,String message){
        Destination queue=new ActiveMQTopic(topicName);
        jmsTemplate.convertAndSend(queue,message);
    }

执行单元测试代码,如下效果

image.png

单元测试代码运行成功,再看下模拟的客户端是否收到消息

image.png

这里可以看到,模拟的设备端已经收到服务器消息。

 

以上就已经介绍完毕,基于ActiveMQ实现MQTT协议的设备接入,数据上传、和对设备的指令下发操作。


想要了解更多信息,可关注本公众号(一起学开源);或请长按以下二维码添加助手。将拉你加入社区进行更多交流

在这里插入图片描述

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起学开源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值