MQTT填坑之旅

来源:互联网 发布:java multiply用法 编辑:程序博客网 时间:2024/06/08 05:38

前言

最近两个项目中都采用了MQTT作为实时消息传输协议,在开发中遇到了不少问题,在这里简单的总结一下,以便记录和帮助大家少走弯路。这篇文章的内容主要来自于https://github.com/emqtt/emqttd 以及http://emqtt.com/。

MQTT是什么

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和制动器(比如通过Twitter让房屋联网)的通信协议。

如何使用MQTT

服务端搭建

本部分将以EMQ为主要介绍对象,EMQ是一个百万级分布式开源物联网MQTT消息服务器。
如下图所示。
这里写图片描述
主要特点如下。

  • 完全开放源码
  • 百万级并发连接
  • 完整MQTT协议支持
  • 简便安装部署
  • 分布式集群或桥接
  • 扩展模块与插件

    EMQ的部署确实相当简单,特别对于windows用户,
    1.http://emqtt.com/downloads 下载windows版本,
    2.解压
    3.在bin目录下运行 emqttd start即可
    4.访问localhost:18083可以知道是否部署成功


tips:
1. EMQ的默认端口:8083 webSocket的端口,18083 工作台端口,1883 后台的通讯端口,8080 API端口
2. EMQ的开源版本是没有数据存储功能的,商业版本是具备数据存储的能力,商业版不便宜,最低的并发版本至少要3W/年。
3. EMQ的工作台是好东西,要充分利用,简单的测试都可以用它
4. EMQ的百万链接并非是并发,这个要注意。
5. MQTT是基于TCP,而MQTT-SN是基于UDP的。


关于数据存储是一个单独的话题,要是并发需求不高可以考虑自己搞一个,原理其实很简单。设定一个管理topic比如tempTopic,若某个topic的消息需要存储则将这个topic发送到tempTopic。再订阅这个topic并将收到的消息持久化即可。
简单流程如下所示
1.订阅tempTopic消息,若收到消息执行下面逻辑
2.订阅收到的消息内容的topic,并将消息内容持久化到数据库中,若收到消息执行下面逻辑
3.将消息内容持久化到数据库中。
4.系统启动时自动监听数据库中tempTopic的消息内容。

Web客户端使用

Web客户端其实就是JS客户端,主要可以用的是Eclipse Paho HTML5 JavaScript over WebSocket和MQTT.js
下面代码以MQTT.js和ES6为例。

import { connect } from 'mqtt';var client  =  connect('ws://localhost:8083/mqtt');client.on('connect', function () {  client.subscribe('presence')  client.publish('presence', 'Hello mqtt')})client.on('message', function (topic, message) {  // message is Buffer  console.log(message.toString())  client.end()})

Java客户端使用

Java客户端则以Eclipse Paho Java为主。

示例

import java.io.FileNotFoundException;import java.io.IOException;import java.security.KeyManagementException;import java.security.KeyStoreException;import java.security.cert.CertificateException;import org.eclipse.paho.client.mqttv3.MqttClient;import org.eclipse.paho.client.mqttv3.MqttConnectOptions;import org.eclipse.paho.client.mqttv3.MqttException;import org.eclipse.paho.client.mqttv3.MqttMessage;import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;public class MqttPublishSample {    public static void main(String[] args) throws KeyManagementException, CertificateException, FileNotFoundException, IOException, KeyStoreException {        String topic        = "MQTT Examples";        String content      = "Message from MqttPublishSample";        int qos             = 2;        String broker       = "ssl://localhost:8883";        String clientId     = "JavaSample";        MemoryPersistence persistence = new MemoryPersistence();        try {            MqttClient sampleClient = new MqttClient(broker, clientId, persistence);            MqttConnectOptions connOpts = new MqttConnectOptions();            connOpts.setCleanSession(true);            System.out.println("Connecting to broker: "+broker);            sampleClient.connect(connOpts);            System.out.println("Connected");            System.out.println("Publishing message: "+content);            MqttMessage message = new MqttMessage(content.getBytes());            message.setQos(qos);            sampleClient.publish(topic, message);            System.out.println("Message published");            client.setCallback(new MqttCallback() {                public void connectionLost(Throwable throwable) {                }                public void messageArrived(String s, MqttMessage mqttMessage) throws  Exception {  System.out.println("Message Arrived");  System.out.println(new String(mqttMessage.getPayload(),"utf-8"));                }                public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {                }            });            sampleClient.disconnect();            System.out.println("Disconnected");            System.exit(0);        } catch(MqttException me) {            System.out.println("reason "+me.getReasonCode());            System.out.println("msg "+me.getMessage());            System.out.println("loc "+me.getLocalizedMessage());            System.out.println("cause "+me.getCause());            System.out.println("excep "+me);            me.printStackTrace();        }     }}

总结

1.clientId不能重复
2.需要数据存储功能的需要结合实际情况是自研还是购买服务
3.需要进行充分的测试,以避免Last Message引起的异常问题
4.对于是否能够满足性能需求一定要实际测试