1. 程式人生 > 實用技巧 >基於mosquitto的嵌入式平臺MQTT訊息推送服務的搭建與使用示例

基於mosquitto的嵌入式平臺MQTT訊息推送服務的搭建與使用示例

2020-12-23

關鍵字:


這篇文章記錄一下在嵌入式平臺搭建MQTT通訊框架的過程。

此框架由PC端ubuntu執行MQTT服務端,或者叫“訊息中介軟體”。在windows端執行一個MQTT客戶端,這個客戶端用於下發訊息到開發板。另有嵌入式linux開發板端執行著自己編寫的程式,通過呼叫mosquitto的介面來實現MQTT訊息訂閱功能。

1、什麼是MQTT和mosquitto

MQTT 全稱是Message Queuing Telemetry Transport,訊息佇列遙測傳輸。是一個開源的輕量級訊息釋出訂閱協議。是專門為硬體效能低下及通訊環境惡劣情況開發的。一句話:MQTT是非常適用於嵌入式平臺的訊息釋出訂閱協議。

MQTT只是一種抽象的協議,實現了這套協議的工具有不少,mosquitto就是其中之一。一句話:通過mosquitto,我們可以開發和使用MQTT軟體進行通訊。

2、嵌入式端環境準備

嵌入式系統原始碼多種多樣,只能使用原始碼自行編譯以生成適用於自己平臺的庫及程式。

mosquitto的原始碼可以在Github上找到,其連結如下:

  https://github.com/eclipse/mosquitto/tags

這裡我們以 2.0.0 版本為例,下載並解壓原始碼。

在編譯之前必須做些配置修改。

首先開啟mosquitto原始碼根目錄下的 Makefile,第一行即可看到如下宣告:

include config.mk

這表明這個Makefile會從原始碼根目錄下的 config.mk 檔案中匯入一些公共配置檔案。事實上,mosquitto 原始碼擁有眾多Makefile,每個主要原始碼都會匯入它,config.mk也是我們要重點配置的物件。

接著看Makefile檔案,再看第二行語句:

DIRS=lib apps client plugins src

這個表示需要編譯的目錄。在本示例中,我們僅需編譯用於嵌入式平臺的mosquitto動態庫,動態庫的原始碼只位於 lib 目錄下,因此,我們可以不編譯其餘目錄,將它們刪去,只保留一個lib目錄,如下所示:

DIRS=lib

事實上,如果我們仍然編譯其它目錄,會遇到很多很讓人頭疼的編譯問題,而這些檔案編出來在本示例中又用不上,乾脆就節省些精力不編譯算了。

至此,原始碼根目錄下的Makefile已經修改完畢了。接下來開啟 config.mk 檔案。按下圖所示修改配置:

然後在UNAME變數之前指定自己平臺的編譯鏈工具名稱,這裡必須注意的是:不同平臺所用到的編譯工具很有可能不一樣,必須根據自己的實際情況來填寫,筆者這裡僅是作個演示,切不可直接照抄,示例寫法如下圖所示:

另外,由於mosquitto需要依賴openssl庫的功能,因此可能需要手動指定屬於你的嵌入式平臺的openssl庫的路徑。同樣地,不同平臺其openssl的存放位置不一樣,必須根據自己的實際情況來填寫,筆者這裡僅作個寫法演示,切勿直接照抄,新增openssl庫路徑的寫法如下圖所示:

然後新增openssl標頭檔案路徑,如下圖所示:

然後再將自帶的 openssl 引用 -lssl 與 -lcrypto 刪掉,如下圖所示:

至此,嵌入式端的配置就修改完畢了。

直接在mosquitto原始碼根目錄下 make 編譯,一般來說稍等片刻即可無錯誤結束編譯。此時可以在 lib 目錄與 lib/cpp 目錄分別發現libmosquitto.so.1 與libmosquittopp.so.1 動態庫檔案的了。我們要用的是libmosquitto.so.1 動態庫。

3、嵌入式端示例程式開發

這裡筆者直接提供一份示例原始碼,原始碼非常簡單,大家直接拿去編譯使用即可。

在合適的位置準備一個目錄,要求目錄內的檔案如下圖所示:

其中 ddemo.c 是筆者下方提供的原始碼。 第二個檔案即是方才編譯出來的動態庫檔案。最後一個檔案是從mosquitto原始碼根目錄下的include目錄下拷貝過來的。相關檔案內容如下所示:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "mosquitto.h"

static void mqtt_connected(struct mosquitto *pstMosq, void *pObject, int iResult, int iFlags, const mosquitto_property *pProperties)
{
    printf("mqtt_connected with:%d\n", iResult);
    mosquitto_subscribe_v5(pstMosq, NULL, "my_mosquitto_topic_20201223", 0, 0, NULL);
    printf("subcribe topic:%s\n", "my_mosquitto_topic_20201223");
}

static void mqtt_disconnected(struct mosquitto *pstMosq, void *pObject, int iReasonCode, const mosquitto_property *pProperties)
{
    printf("mqtt_disconnected with: %d\n", iReasonCode);
    return ;
}

void mqtt_msg(struct mosquitto *msqt, void *pObject, const struct mosquitto_message *msg, const mosquitto_property *pProperties)
{
    printf("Got a message!\n");
    printf("Topic:\n\t%s\n", msg->topic);
    printf("Data length:\n\t%d\n", msg->payloadlen);
    printf("Data:\n\t%s\n\n", (char*)msg->payload);
}

int main()
{
    struct mosquitto* msqt = NULL;
    
    mosquitto_lib_init();
    msqt = mosquitto_new("mosquitto_demo_id", 0, NULL);
    mosquitto_connect_v5_callback_set(msqt, mqtt_connected);
    mosquitto_disconnect_v5_callback_set(msqt, mqtt_disconnected);
    mosquitto_message_v5_callback_set(msqt, mqtt_msg);
    mosquitto_username_pw_set(msqt, "user1", "123456");
    mosquitto_connect_bind_v5(msqt, "192.168.77.30", 1883, 30, NULL, NULL);
    
    mosquitto_loop_forever(msqt, 2000, 1);
    
    mosquitto_destroy(msqt);
    mosquitto_lib_cleanup();

    return 0;
}
ddemo.c原始碼

CC = msdk-linux-gcc

all: mosquitto_demo
    

mosquitto_demo:ddemo.c
    $(CC) -c -g $^
    $(CC) ddemo.o -I. -L../mosquitto-2.0.0/lib libmosquitto.so.1 -L../../openssl-1.0.2d  -lssl -lcrypto -lpthread -o $@

clean:
    -rm *.o
    -rm mosquitto_demo
Makefile原始碼

此時便可編譯示例程式了。

直接在示例程式原始碼根目錄下以 make 命令編譯。一般都能直接編過。如果很不幸,你遇到了如下所示的錯誤:

[demo]$ make
msdk-linux-gcc -c -g ddemo.c
msdk-linux-gcc ddemo.o -I. -L../mosquitto-2.0.0/lib libmosquitto.so.1 -L../../openssl-1.0.2d  -lssl -lcrypto -lpthread -o mosquitto_demo
libmosquitto.so.1: undefined reference to `pthread_setname_np'
collect2: ld returned 1 exit status
make: *** [mosquitto_demo] Error 1

這需要回到 mosquitto 原始碼去註釋掉一條語句。

開啟 mosquitto-2.0.0/lib/thread_mosq.c,將第47行的程式碼註釋掉,如下圖所示:

重新編譯 mosquitto,將編譯出來的庫拷貝至示例程式碼目錄下再次編譯便可通過的了。

將mosquitto動態庫與示例程式下載至開發板中。

至此,整個嵌入式端的環境均已準備好。

4、MQTT服務端搭建

MQTT服務端在PC機的ubuntu上搭建。這裡筆者直接參考另一位大神的博文步驟了,原文連結如下:

  https://www.cnblogs.com/lulipro/p/10914482.html

這裡將關鍵的步驟提取出來,圖省事的同學直接把下面的命令逐一執行一次即可。另,筆者的PC環境為 ubuntu 14.04.06。

sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa     #新增源到軟體倉庫
sudo apt-get update                                         #更新軟體倉庫列表
sudo apt-get install mosquitto                              #安裝mosquitto

sudo service mosquitto status                               #檢視執行狀態
sudo service mosquitto start                                #啟動服務
sudo service mosquitto stop                                 #停止服務

sudo service mosquitto stop   #首先停止服務

#使用者的區域性配置檔案放在: /etc/mosquitto/conf.d/目錄下,並且這個目錄下的所有以.conf字尾的檔案都將被mosquitto作為配置檔案,在啟動時載入。

#在/etc/mosquitto/conf.d目錄下,新建myconfig.conf配置檔案

#在其中輸入如下內容
#-------------------------------------------
# 關閉匿名訪問,客戶端必須使用使用者名稱
allow_anonymous false

#指定 使用者名稱-密碼 檔案
password_file /etc/mosquitto/pwfile.txt
#--------------------------------------------

假設使用者名稱為:user1
在命令列執行:mosquitto_passwd -c /etc/mosquitto/pwfile.txt user1

回車後連續輸入2次使用者密碼即可

sudo service mosquitto start      #啟動服務

至此,PC端的MQTT服務端,或者說“訊息中介軟體”環境也已搭建好了。

此時,我們還差最後一個角色:用於釋出訊息的程式。當然我們可以以前面那位大神文章中提到的直接使用IOS端的 MQTTool 工具。但筆者其實更推薦使用PC端的工具,這裡直接使用 eclipse 出品的windows端MQTT工具了。下載地址如下:

  https://repo.eclipse.org/content/repositories/paho-releases/org/eclipse/paho/org.eclipse.paho.ui.app/1.0.2/

這裡我們根據自己的機器下載相應版本軟體,如下圖所示:

下載解壓後即可直接使用。

5、除錯

至此,所有環境都已經準備好,可以開始聯合除錯了。

首先將嵌入式開發板端自己編寫的示例程式執行起來,這裡必須注意,必須要根據自己的實際情況填寫MQTT伺服器IP地址。在地址與埠號配置正確的情況下執行示例可以可以發現如下列印資訊:

如果無法正常連線,請檢查:1、網路環境;2、示例程式中的配置資訊;3、MQTT服務端是否正確安裝並配置。

其次開啟windows端的MQTT工具,首次開啟軟體需要點選克上角的新建連線按鈕,如下圖所示:

填寫好資訊後連線伺服器,並準備訊息主題及內容資訊,操作步驟如下圖所示:

在第5步點選了“釋出”按鈕後,即可立即在開發板端看到如下列印:

此結果即表示我們的目的已經達成。


參考資料:

  https://www.cnblogs.com/lulipro/p/10914482.html