基于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
", iResult);
    mosquitto_subscribe_v5(pstMosq, NULL, "my_mosquitto_topic_20201223", 0, 0, NULL);
    printf("subcribe topic:%s
", "my_mosquitto_topic_20201223");
}

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

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

", (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

原文地址:https://www.cnblogs.com/chorm590/p/14167252.html