背景
现今已进入如火如荼的物联网时代,万物互联,设备从信息化走向数字化时代。生活中随处可见物联网的产品的应用场景;智能家居、智慧物业、智慧园区、智慧城市等。
作为专业的技术工程师,我们需要了解行业发展,支持行业技术应用构建的核心技术,提升自己在技术全都核心竞争力。
本章将重点介绍基于开源软件,我们如何快速实现设备的联网。
准备阶段
结构图如下
搭建MQTT服务器
此处以ActiveMQ服务器为例进行介绍。前面章节我们已经介绍了ActiveMQ产品的安装,此处主要介绍如何查看ActiveMQ是否支持MQTT协议
进入到ActiveMQ安装目录,打开对应应用程序的conf文件夹,打开activemq.xml
打开ActiveMQ,注意看一下activemq.xml文件中红色部分是否有被注释掉
启动服务,通过命令进入到ActiveMQ的 bin目录,执行如下脚本,已启动ActiveMQ服务器
./activemq start
即可得到如下的打印信息,则启动正常
准备好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工具模拟设备端的链接,先启动软件
设置服务器参数(参照如下指引设置,然后apply即可;说明:第3步,服务器默认用户名密码是 admin、admin)
如上图所示,主要4步
- 设置连接名称
- 设置服务器地址和端口以及客户端名称(默认端口1883,客户端名称暂时可以随机生成)
- 设置用户名密码(默认是admin/admin)
- 直接保存应用(Apply)
再回到主界面,点击链接connect按钮,链接服务器
如上图所示,操作步䠫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
服务器端选定设备并下发指令,单元测试代码如下
/*** * 发送消息到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); }
执行单元测试代码,如下效果
单元测试代码运行成功,再看下模拟的客户端是否收到消息
这里可以看到,模拟的设备端已经收到服务器消息。
以上就已经介绍完毕,基于ActiveMQ实现MQTT协议的设备接入,数据上传、和对设备的指令下发操作。
想要了解更多信息,可关注本公众号(一起学开源);或请长按以下二维码添加助手。将拉你加入社区进行更多交流