最近项目中有一个需求,要用mqtt协议接收路侧设备的数据到云平台上,所以,研究了一下mqtt客户端的制作方法。

mqtt协议是一个发布订阅模式的协议。

这篇文章主要记录下我搭建mqttbroker和写mqtt客户端的过程,是记录,不是教程,无意教程。

一、下载安装emqx

emqx是一个mqtt的broker软件,这个软件是比较好用的一个broker软件,以前用过mosquitto软件做mqtt的broker,但是mosquitto没有emqx易用,所以就放弃了。

从emqx的官网上下载得到emqx-4.4.1-otp24.1.5-3-el7-amd64.zip,unzip解压出来一个emqx的文件夹。

进入到emqx/bin下执行 emqx start,就将emqx启动起来了。

[root@localhost bin]# ./emqx start
WARNING: There seem to be missing dynamic libs from the OS. Using libs from /root/emqx/dynlibs
EMQ X Broker 4.4.1 is started successfully!
[root@localhost bin]#

查看emqx的运行状态用bin下的emqx_ctl命令。

[root@localhost bin]# ./emqx_ctl status
Node 'emqx@127.0.0.1' 4.4.1 is started
[root@localhost bin]#

经过以上的下载、解压、启动、查看状态四个步骤,就将emqx软件正常运行起来了。

二、mqtt客户端的编写

编写mqtt客户端,是需要eclips的paho库的,这个库是一个mqtt客户端的编程接口库。

在基于maven的java项目中,要增加一个dependency。

<dependency>
            <groupId>org.eclipse.paho</groupId>
            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
            <version>1.2.2</version>
</dependency>

接下来就是写client的代码了。

下面的代码中有发送消息的代码,也有接收消息的代码,接收消息的代码就是那个OnMessageCallback,有了这个Callback类就可以接收mqtt消息了。

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;

import java.nio.charset.StandardCharsets;


public class App {
    public static void main(String[] args) {
        String subTopic = "testtopic/#";
        String pubTopic = "testtopic/1";
        String content = "哈哈哈,我又来了。";
        int qos = 2;
        String broker = "tcp://123.56.182.37:1883"; //这里是broker的地址
        String clientId = "emqx_test";
        MemoryPersistence persistence = new MemoryPersistence();

        try {
            MqttClient client = new MqttClient(broker, clientId, persistence);

            // MQTT 连接选项
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setUserName("emqx_test");
            connOpts.setPassword("emqx_test_password".toCharArray());
            // 保留会话
            connOpts.setCleanSession(true);

            // 设置回调,这个回调类是用来接收mqtt消息的,如果只是想要发布mqtt消息,那么就不需要这个回调了。
            // 当然,如果只是想接收mqtt消息,不想发送,那么就只设置这个回调,下面的发送代码也就不需要了
            client.setCallback(new OnMessageCallback());

            // 建立连接
            System.out.println("Connecting to broker: " + broker);
            client.connect(connOpts);

            System.out.println("Connected");
            System.out.println("Publishing message: " + content);

            // 订阅
            client.subscribe(subTopic);

            // 消息发布所需参数
            long i = 0;
            while (i < 10e10) {
                MqttMessage message = new MqttMessage(content.getBytes(StandardCharsets.UTF_8));
                message.setQos(qos);
                client.publish(pubTopic, message);

                Thread.sleep(10000);
                i++;

                System.out.println("Message published, i = " + i);
            }

            client.disconnect();
            System.out.println("Disconnected");
            client.close();
            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();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;

public class OnMessageCallback implements MqttCallback {
    public void connectionLost(Throwable cause) {
        // 连接丢失后,一般在这里面进行重连
        System.out.println("连接断开,可以做重连");
    }

    public void messageArrived(String topic, MqttMessage message) throws Exception {
        // subscribe后得到的消息会执行到这里面
        System.out.println("接收消息主题:" + topic);
        System.out.println("接收消息Qos:" + message.getQos());

        System.out.println("接收消息内容:" + new String(message.getPayload(), "utf-8"));
    }

    public void deliveryComplete(IMqttDeliveryToken token) {
        System.out.println("deliveryComplete---------" + token.isComplete());
    }
}

以上两步就可以完成一个具备基本功能的mqtt协议客户端了,这个客户端既可以发布消息,也可以接收消息。当然,如果只想要一个方面的功能,也可以适当裁剪以适应自己的需要。

参考资料:
1、https://www.emqx.io/docs/zh/v4.4/getting-started/install.html