基於ActiveMq服務器Paho Java客戶端的MQTT消息訂閱與發送

Java基於ActiveMq 客戶端的MQTT實現

MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸協議),是一種基於發佈/訂閱(publish/subscribe)模式的“輕量級”通訊協議,MQTT消息的發送和訂閱都是依賴MQTT服務器的,沒有MQTT服務器,你的客戶端是無法訂閱和發送消息的。所以在最開始的時候,可以選擇性的在你的電腦上面安裝一個MQTT服務器。

這裏需要了解一些概念:

(1)MQTT協議實現方式

實現MQTT協議需要客戶端和服務器端通訊完成,在通訊過程中,MQTT協議中有三種身份:發佈者、代理、訂閱者,其中消息的發佈者和訂閱者都是客戶端,消息代理是服務器,消息發佈者也可以是訂閱者。

MQTT傳輸的消息分爲:主題(Topic)和負載(payload)兩部分:

主題:可以理解爲消息的類型,訂閱者訂閱(Subscribe)後,就會收到該主題的消息內容(payload)
負載:可以理解爲消息內容,是指的訂閱者具體收到的數據。
(2)MQTT客戶端
發佈消息給其它相關的客戶端。
訂閱以請求接受相關的消息。
取消訂閱以移除接受消息的請求。
從服務端斷開連接
(3)服務器
接受來自客戶端的網絡連接。
接受客戶端發佈的應用消息。
處理客戶端的訂閱和取消訂閱請求。
轉發應用消息給符合條件的已訂閱客戶端。

MQ是消息中間件,是一種在分佈式系統中應用程序藉以傳遞消息的媒介,常用的有ActiveMQ,RabbitMQ,kafka。ActiveMQ是Apache下的開源項目,完全支持JMS1.1和J2EE1.4規範的JMS Provider實現。 (我們這裏使用的ActiveMQ)

1 安裝apache-activemq

(1) http://activemq.apache.org 進行下載需要的版本,這裏是安裝在Windows上,下載好的壓縮包,進行解壓。
在這裏插入圖片描述(2)進入到指定目錄,運行/bin/win32或win64 activemq.bat
在這裏插入圖片描述(3)這樣我們的ActiveMq 就運行,然後在瀏覽器中輸入http://localhost:8161 剛開始需要登錄,初始賬號h和密碼:admin ,這樣服務器就部署好了。
在這裏插入圖片描述

2 業務需求

具體的實現方式,根據業務不同,代碼邏輯不同,我這裏定義了設備信息採集的客戶端,和接收所有設備信息的服務端,
(1)客戶端設備信息能實時上傳
(2)客戶端可以實時獲取最新的設備參數等數據
(3)服務器能實時更新設備參數和加載最新數據
(4)其他需求

3 具體實現

(1)瞭解Paho
Paho Java客戶端是一個用Java編寫的MQTT客戶端庫,用於開發在JVM或其他Java兼容平臺(如Android)上運行的應用程序。
Paho Java客戶端提供了兩個API:MqttAsyncClient提供了一個完全異步的API,通過已註冊的回調通知完成活動。 MqttClient是MqttAsyncClient的一個同步包裝,其中函數與應用程序同步。
(2)添加依賴

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

不管是客戶端還是服務端都要加,對於paho不存在客戶端和服務端,消息的訂閱與發送都是可以,只是通過代碼的業務邏輯實現,有些消息只有客戶端能訂閱和發送,有些消息只有服務端能訂閱和發送。
(3)連接 MqttClient
在程序加載的時候啓動線程,連接mqtt服務器,完成一些數據初始化操作
1 連接mqtt

 	private MqttClient client;
    private JedisClient jedisClient;
    private String scanSrc;
    private IWorkshopAlarmDao alarmDao;
    private String mqttHost;
    private String clientId;
    private String userName;
    private String passWord;
    private MqttConnectOptions options;
    private int qos = 2;
     public void run(){
        try {
            System.out.println("連接MQTT服務。。。。。");
            connectMqtt();
            startServer();
            System.out.println("MQTT 訂閱服務。。。。。");

        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void connectMqtt(){
        try {
//            client = new MqttAsyncClient(mqttHost, clientId, new MemoryPersistence());
            client = new MqttClient(mqttHost, clientId, new MemoryPersistence());
            options = new MqttConnectOptions();
            options.setCleanSession(true);
            options.setUserName(userName);
            options.setPassword(passWord.toCharArray());
            // 設置超時時間
            options.setConnectionTimeout(10);
            // 設置會話心跳時間
            options.setKeepAliveInterval(90);
            client.setCallback(new PublishMessage());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2 設置斷開重連

public void startServer() {
        try {
            while (true) {
                try {
                    //判斷攔截狀態,這裏注意一下,如果沒有這個判斷,是非常坑的
                    if (!client.isConnected()) {
                        System.out.println("*****嘗試連接mqtt *****");
                        client.connect(options);
                    }
                    if (client.isConnected()) {//連接成功,跳出連接
                        System.out.println("*****已連接mqtt success *****");
                        break;
                    }
                    sleep(2000);
                } catch (MqttException e1) {
                    System.out.println("連接MQTT服務失敗。。。。。。。。。。。。");
                }
            }
            //訂閱消息
            subTopic();
            initMessage();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3 在初始化的時候需要訂閱消息topic

 public void subTopic(){
        //訂閱消息
        int[] Qos  = {qos};
//        String[] reg_workshop = {TopicConst.reg_workshop};
//        String[] reg_aiservice = {TopicConst.reg_aiservice};
//        String[] reg_camera = {TopicConst.reg_camera};
//        String[] reg_gate = {TopicConst.reg_gate};
        String[] init_reg = {TopicConst.init_reg};
        String[] get_worker = {TopicConst.get_worker};
        String[] update_workshop = {TopicConst.update_workshop};
        String[] update_aiservice = {TopicConst.update_aiservice};
        String[] update_camera = {TopicConst.update_camera};
        String[] update_gate = {TopicConst.update_gate};
        String[] workshop_record = {TopicConst.workshop_record};
        String[] delete_gate = {TopicConst.delete_gate};
        String[] delete_camera = {TopicConst.delete_camera};
        String[] workshop_reset = {TopicConst.workshop_reset};
        try {
//            client.subscribe(reg_workshop, Qos);
//            client.subscribe(reg_aiservice, Qos);
//            client.subscribe(reg_camera, Qos);
//            client.subscribe(reg_gate, Qos);
            client.subscribe(get_worker, Qos);
            client.subscribe(update_workshop, Qos);
            client.subscribe(update_aiservice, Qos);
            client.subscribe(update_camera, Qos);
            client.subscribe(update_gate, Qos);
            client.subscribe(workshop_record, Qos);
            client.subscribe(delete_gate, Qos);
            client.subscribe(delete_camera, Qos);
            client.subscribe(init_reg, Qos);
            client.subscribe(workshop_reset, Qos);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

4 消息接收,業務邏輯處理

class PublishMessage implements MqttCallback {
        public void connectionLost(Throwable cause) {
            // 連接丟失後,一般在這裏面進行重連
            System.out.println("連接斷開,可以做重連");
//            connectMqtt();
            StopService();
            startServer();
        }

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

        public void messageArrived(String topic, MqttMessage message) {
            // subscribe後得到的消息會執行到這裏面
            byte[] messByte = message.getPayload();
            System.out.println("接收消息主題 : " + topic);
            System.out.println("接收消息Qos : " + message.getQos());
            try {
//                System.out.println("接收消息內容 : " + new String(messByte).getBytes("utf8"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (topic == null) {
                return;
            }
            try {
                String data = new String(messByte, "utf-8");
                if (topic.equals(TopicConst.init_reg)) {
                    initReg(data);
                } else if (topic.equals(TopicConst.update_workshop)) {
                    updateWorkShop(data);
                } else if (topic.equals(TopicConst.update_aiservice)) {
                    updateAiservier(data);
                } else if (topic.equals(TopicConst.update_camera)) {
                    updateCamera(data);
                } else if (topic.equals(TopicConst.update_gate)) {
                    updateGate(data);
                } else if (topic.equals(TopicConst.get_worker)) {
                    if (data.equals("1")) {
                        sendWorker();
                    }
                } else if (topic.equals(TopicConst.workshop_record)) {
                    reportRecords(data);
                } else if (topic.equals(TopicConst.delete_gate)) {
                    deleteGate(data);
                } else if (topic.equals(TopicConst.delete_camera)) {
                    deleteCamera(data);
                }else if (topic.equals(TopicConst.workshop_reset)) {
                    resetWorkShop(data);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

5 發送消息

public void publish(MqttTopic topic , MqttMessage message) throws  MqttException {
        MqttDeliveryToken token = topic.publish(message);
        token.waitForCompletion();
        System.out.println("message is published completely! " + token.isComplete());
    }

6 服務斷開做相關處理

public void StopService() {
        try {
            if(client !=null){
                // 斷開連接
                client.disconnect();
                // 關閉客戶端
                client.close();
            }

        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

這裏沒有做相關Mqtt 服務,而是把消息訂閱與分佈和具體的業務代碼融合。

使用org.eclipse.paho 工具進行消息的訂閱和發送

在這裏插入圖片描述工具的使用很簡單,不說明。

發佈了9 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章