Mqtt实现发布订阅-简单案例

Mqtt实现发布订阅-简单案例

当你看到这边文章是想必你也是刚开始学习mqtt,也许你对于什么是mqtt还不是太了解,建议去把mqtt的入门介绍(点击跳转)看一下,了解清楚后再来学习,效果会更好

正式学习之前还需要搭建一个mqtt的服务器,本文用的是apache-apollo mqtt服务器安装教程

1.所需要的maven依赖

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

1.实现一个mqtt客户端类

package com.mochen.mqtt.entity;

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author 
 * @date 2020-11-25 14:59
 * @Description:
 */


public class MyMqttClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyMqttClient.class);
    private static MqttClient client;

    private String host;
    private String username;
    private String password;
    private String clientId;
    private int timeout;
    private int keepalive;


    public static MqttClient getClient() {
        return client;
    }

    public static void setClient(MqttClient client) {
        MyMqttClient.client = client;
    }


    public MyMqttClient(String host, String username, String password, String clientId, int timeout, int keepalive) {
        this.host = host;
        this.username = username;
        this.password = password;
        this.clientId = clientId;
        this.timeout = timeout;
        this.keepalive = keepalive;
    }

    /**
     * 设置连接属性
     *
     * @param username
     * @param password
     * @param timeout
     * @param keepalive
     * @return
     */
    public MqttConnectOptions setMqttConnectOptions(String username, String password, int timeout, int keepalive) {
        MqttConnectOptions options = new MqttConnectOptions();
        //用户名
        options.setUserName(username);
        //密码
        options.setPassword(password.toCharArray());
        // 设置超时时间 单位为秒
        options.setConnectionTimeout(timeout);
        // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
        options.setKeepAliveInterval(keepalive);
        // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
        options.setCleanSession(false);
        //设置断开后重新连接
        options.setAutomaticReconnect(true);
        return options;
    }

    /**
     * 连接mqtt服务端,得到MqttClient连接对象
     */
    public void connect() throws MqttException {
        if (client == null) {
            //clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
            client = new MqttClient(host, clientId, new MemoryPersistence());
            client.setCallback(new PushCallback(MyMqttClient.this));
        }
        MqttConnectOptions mqttConnectOptions = setMqttConnectOptions(username, password, timeout, keepalive);
        if (!client.isConnected()) {
            client.connect(mqttConnectOptions);
        } else {
            client.disconnect();
            client.connect(mqttConnectOptions);
        }

    }

    /**
     * 发布,默认qos为0,非持久化
     *
     * @param pushMessage
     * @param topic
     */
    public void publish(String pushMessage, String topic) {
        publish(pushMessage, topic, 0, false);
    }

    /**
     * 发布消息
     *
     * @param pushMessage
     * @param topic
     * @param qos
     * @param retained:留存
     */
    public void publish(String pushMessage, String topic, int qos, boolean retained) {
        MqttMessage message = new MqttMessage();
        message.setPayload(pushMessage.getBytes());
        message.setQos(qos);
        //retained为true表示会去取之前还未消费的数据,为false只取最新接收的消息
        message.setRetained(retained);
        MqttTopic mqttTopic = MyMqttClient.getClient().getTopic(topic);
        if (null == mqttTopic) {
            LOGGER.error("topic is not exist");
        }
        MqttDeliveryToken token;//Delivery:配送
        synchronized (this) {//注意:这里一定要同步,否则,在多线程publish的情况下,线程会发生死锁
            try {
                token = mqttTopic.publish(message);//也是发送到执行队列中,等待执行线程执行,将消息发送到消息中间件
                token.waitForCompletion(1000L);
            } catch (MqttPersistenceException e) {
                e.printStackTrace();
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 订阅某个主题,qos默认为0
     *
     * @param topic
     */
    public void subscribe(String topic) {
        subscribe(topic, 0);
    }

    /**
     * 订阅某个主题
     *
     * @param topic
     * @param qos   0:最多一次 、1:最少一次 、2:只有一次
     */
    public void subscribe(String topic, int qos) {
        try {
            MyMqttClient.getClient().subscribe(topic, qos);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }


}

  1. mqtt回调类
package com.mochen.mqtt.entity;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author 
 * @date 2020-11-25 14:53
 * @Description:
 */
public class PushCallback implements MqttCallback {
    private static final Logger LOGGER = LoggerFactory.getLogger(PushCallback.class);

    private MyMqttClient myMqttClient;

    public PushCallback(MyMqttClient myMqttClient) {
        this.myMqttClient = myMqttClient;
    }


    /**
     * 连接丢失:一般用与重连
     *
     * @param throwable
     */
    @Override
    public void connectionLost(Throwable throwable) {
        long reconnectTimes = 1;

        while (true) {
            try {
                if (MyMqttClient.getClient().isConnected()) {
                    LOGGER.warn("mqtt reconnect success end");
                    return;
                }
                LOGGER.warn("mqtt reconnect times = {} try again...", reconnectTimes++);
                MyMqttClient.getClient().reconnect();
            } catch (MqttException e) {
                LOGGER.error("", e);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                //e1.printStackTrace();
            }
        }

    }

    /**
     * subscribe后得到的消息会执行到这里面
     *
     * @param topic
     * @param message
     * @throws Exception
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {

        System.out.println("主题:" + topic + ",接收消息内容 : " + new String(message.getPayload()));
    }

    /**
     * (发布)publish后会执行到这里,发送状态
     *
     * @param iMqttDeliveryToken
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

    }
}

4.测试发布、订阅

package com.mochen.mqtt.controller;

import com.mochen.mqtt.entity.MyMqttClient;
import org.junit.Test;

/**
 * @author 
 * @date 2020-11-25 16:04
 * @Description:
 */
public class TestMqtt {

    /**
     * 分级发布与订阅
     *
     * @throws Exception
     */
    String topicName1 = "topic7";

    //订阅
    @Test
    public void testTopic() throws Exception {
        MyMqttClient myMqttClient = new MyMqttClient("tcp://127.0.0.1:61613", "admin", "password", "mqttClient2", 10, 20);
        myMqttClient.connect();
        myMqttClient.subscribe(topicName1);
        while (true);
    }

    //发布
    @Test
    public void testTopic2() throws Exception {
        MyMqttClient myMqttClient = new MyMqttClient("tcp://127.0.0.1:61613", "admin", "password", "mqttClient4", 10, 20);
        myMqttClient.connect();
        int count = 10000;
        for (int i = 0; i < count; i++) {
            myMqttClient.publish(topicName1 + "发送消息"+i, topicName1, 1, true);
        }

    }
}

本文参考了网上几篇博客,最后亲自编写测试通过
参考:
参考博客一
参考博客二

最后附上这个demo的 github源码下载地址:https://github.com/mochengyifen/mqtt.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值