目录
前言
嵌入式单片机与Linux学习:
- 可以观看b站韦东山老师的课程,全网第一!!!
参考资料:
-
kawaii-mqtt源码:
-
博客
-
APP
一、MQTT协议
1.MQTT协议简介
MQTT协议全称是Message Queuing Telemetry Transport,翻译过来就是消息队列遥测传输协议,它是物联网常用的应用层协议,运行在TCP/IP中的应用层中,依赖TCP协议,因此它具有非常高的可靠性,同时它是基于TCP协议的 <客户端-服务器> 模型发布/订阅主题消息的轻量级协议,也是我们常说的发送与接收数据,下面我们来初步了解一下mqtt相关的名称与功能。
2.MQTT通信模型
MQTT 协议提供一对多的消息发布,可以降低应用程序的耦合性,用户只需要编写极少量的应用代码就能完成一对多的消息发布与订阅,该协议是基于<客户端-服务器>模型,在协议中主要有三种身份:发布者(Publisher)、服务器(Broker)以及订阅者(Subscriber)。其中,MQTT消息的发布者和订阅者都是客户端,服务器只是作为一个中转的存在,将发布者发布的消息进行转发给所有订阅该主题的订阅者;发布者可以发布在其权限之内的所有主题,并且消息发布者可以同时是订阅者,实现了生产者与消费者的脱耦,发布的消息可以同时被多个订阅者订阅。
MQTT通信模型示意图如下:
(1)MQTT客户端功能
- 1.发布消息给其他相关的客户端
- 2.订阅主题请求接收相关的应用消息
- 3.取消订阅主题请求移除接收应用消息
- 4.从服务端终止连接
(2)MQTT
MQTT服务器通常被称为 Broker(消息代理),是一个应用程序或一台设备,它一般为云服务器,比如BTA三巨头的一些物联网平台就是常使用MQTT协议,它是位于消息发布者和订阅者之间,以便用于接收消息并发送到订阅者之中,它的功能有:
- 1.接收来自客户端的网络连接请求
- 2.接收客户端发布的应用消息
- 3.处理客户端的订阅和取消订阅请求
- 4.转发应用消息给符合条件的已订阅的客户端(包括发布者自身)
3.消息主题与服务质量
什么是主题?
MQTT服务器为每个连接的客户端(订阅者)添加一个标签,该标签与服务器中的所有订阅相匹配,服务器会将消息转发给与标签相匹配的每个客户端(订阅者),当然订阅者也是需要有权限才能订阅对应的主题,比如像阿里云中的,订阅者只能订阅同一个产品下的主题,而不能跨产品订阅,这样子的处理就能达到信息的安全性以及多个订阅者能及时收到消息。一个主题可以有多个级别,各个级别之间用斜杠字符分隔,例如/test 和 /test/test1/test2都 是有效的主题。
发布者与订阅者可以通过主题名字,一般为UTF-8编码(反正用英文字符串就不会错)的形式发布和订阅主题,比如我们可以直接定义一个名字为“test”的主题,绝大多数的MQTT服务器支持动态发布/定阅主题,即当前服务器中没有某个主题,但是客户端直接可以向该主题发布/订阅消息,这样子服务器就会创建对应的主题,当然,服务器中一般也会默认提供多个系统主题,所有连接的客户端均可订阅。
每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间会有状态交互,订阅是基于会话之上,每个订阅中,都会包含一个主题过滤器,它是一个表达式,用于标识订阅相关的一个或多个主题,主题过滤器可以使用通配符,因此订阅者需要指定订阅的主题名字与服务质量(QoS),订阅者能订阅多个主题,也就能接收到多个发布者发布的消息。同理,发布者也需要首先与服务器建立会话,并且指定发送的主题名字与服务质量,同时它也能向多个不同的主题发送消息。
那么什么是服务质量呢?
MQTT的服务质量提供3个等级:
- QoS0:最多发送一次消息,在消息发送出去后,接收者不会发送回应,发送者也不会重发消息,消息可能送达一次也可能根本没送达,这个服务质量常用在不重要的消息传递中,因为即使消息丢了也没有太大关系。
- QoS1:最少发送一次消息(消息最少需要送达一次,也有可送达多次),QoS 1的PUBLISH报文的可变报头中包含一个报文标识符,需要PUBACK报文确认。即需要接收者返回PUBACK应答报文。
- QoS2:这是最高等级的服务质量,消息丢失和重复都是不可接受的,只不过使用这个服务质量等级会有额外的开销,这个等级常用于支付中,因为支付是必须有且仅有一次成功,总不能没给钱或者给了多次钱吧。
二、搭建 MQTT Broker
我们在使用MQTT协议时可以使用别人搭建好的服务器,也可以自己搭建服务器。
步骤如下:
1.进入mosquitto-2.0.14-install-windows-x64的安装目录,修改配置文件mosquitto.conf,如下修改:
# listener port-number [ip address/host name/unix socket path]
listener 1883
allow_anonymous true
2.右键打开命令提示符,输入以下命令:
.\mosquitto.exe -c mosquitto.conf -v
若出现以下情况:端口被占用
输入以下命令尝试杀死该进程:
netstat -aon|findstr 1883
tasklist /fi “pid eq 6412”
taskkill /pid 6412 /f
如果显示拒绝访问,那我们只能打开任务管理器,将它关掉:
然后重新执行以下命令就可以成功:
.\mosquitto.exe -c mosquitto.conf -v
三、在开发板上使用MQTT
1.使用库编译程序
执行以下命令,拉取源码和安装cmake库:
git clone https://github.com/jiejieTop/mqttclient.git
sudo apt-get install cmake g++
下载成功后进入目录,执行以下命令编译对应库:
./make-libmqttclient.sh
可以得到./libmqttclient/lib/libmqttclient.so
或者直接进入该目录 make 也可以得到libmqttclient.so
在这里我已经写好测试源码和Makefile,只需要进入编译成功后的libmqttclient目录下,将测试源码 mqtt_test.c 和 Makefile 放进该目录,然后执行make命令即可编译成功ARM架构可执行程序。
测试源码mqtt_test.c:
/*
* @Author: jiejie
* @Github: https://github.com/jiejieTop
* @Date: 2019-12-11 21:53:07
* @LastEditTime : 2022-06-15 23:03:30
* @Description: the code belongs to jiejie, please keep the author information and source code according to the license.
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <pthread.h>
#include "mqtt_config.h"
#include "mqtt_log.h"
#include "mqttclient.h"
//#include "ca.inc"
// #define TEST_USEING_TLS
static void topic1_handler(void* client, message_data_t* msg)
{
(void) client;
MQTT_LOG_I("-----------------------------------------------------------------------------------");
MQTT_LOG_I("%s:%d %s()...\ntopic: %s\nmessage:%s", __FILE__, __LINE__, __FUNCTION__, msg->topic_name, (char*)msg->message->payload);
MQTT_LOG_I("-----------------------------------------------------------------------------------");
}
void *mqtt_publish_thread(void *arg)
{
mqtt_client_t *client = (mqtt_client_t *)arg;
int cnt = 0;
char buf[100] = { 0 };
mqtt_message_t msg;
memset(&msg, 0, sizeof(msg));
sprintf(buf, "welcome to mqttclient, this is a publish test...");
sleep(2);
mqtt_list_subscribe_topic(client);
msg.payload = (void *) buf;
while(1) {
//sprintf(buf, "smarthome-test %d", cnt++);
sprintf(buf, "smarthome-test, %d", cnt++);
msg.qos = 0;
mqtt_publish(client, "oled_test", &msg);
msg.qos = 1;
mqtt_publish(client, "led_test", &msg);
msg.qos = 2;
mqtt_publish(client, "dht11_test", &msg);
sleep(4);
}
}
int main(void)
{
int res;
pthread_t thread1;
mqtt_client_t *client = NULL;
char client_id[32];
char user_name[32];
char password[32];
printf("\nwelcome to mqttclient test...\n");
random_string(client_id, 10);
random_string(user_name, 10);
random_string(password, 10);
mqtt_log_init();
client = mqtt_lease();
#ifdef TEST_USEING_TLS
mqtt_set_port(client, "8883");
mqtt_set_ca(client, (char*)test_ca_get());
#else
mqtt_set_port(client, "1883");
#endif
// mqtt_set_host(client, "120.25.213.14");
mqtt_set_host(client, "192.168.5.10");
mqtt_set_client_id(client, client_id);
mqtt_set_user_name(client, user_name);
mqtt_set_password(client, password);
mqtt_set_clean_session(client, 1);
mqtt_connect(client);
mqtt_subscribe(client, "topic1", QOS0, topic1_handler);
mqtt_subscribe(client, "topic2", QOS1, NULL);
mqtt_subscribe(client, "topic3", QOS2, NULL);
res = pthread_create(&thread1, NULL, mqtt_publish_thread, client);
if(res != 0) {
MQTT_LOG_E("create mqtt publish thread fail");
exit(res);
}
while (1) {
sleep(100);
}
}
Makefile:
all:mqtt_test.c
arm-buildroot-linux-gnueabihf-gcc -o mqtt_test mqtt_test.c -I ./include/config -I ./include/common -I ./include/common/log -I ./include/mqttclient -I ./include/mqtt -I ./include/platform/linux -I ./include/network -lpthread -L . -lmqttclient
clean:
rm mqtt_test
2.把MQTT源码移植到自己工程
我们可以使用Makefile或者CMake管理自己的工程,在这里我使用的是Makefile。
执行以下命令拉取源码:
git clone https://github.com/jiejieTop/mqttclient.git
然后可以删掉一些不需要的文件,将其打包上传到 Windows 进行管理:
tar cjf mqttclient.tar.bz2 mqttclient
在 Windows 编写修改程序后重新上传到 Ubuntu 上编译:
执行以下命令打包:
tar cjf mqtt_to_imx6ull_test_ok.tar.bz2 mqtt_to_imx6ull_test_ok
完整代码我上传到资源里了,链接如下:
3.上机测试
上电Linux开发板,将编译生成的可执行文件上传到开发板,在开发板的 /usr/lib目录下或者 /lib 目录下存放mqtt相关的库,或者直接指定路径:
cp libmqttclient.so /usr/lib
or
export LD_LIBRARY_PATH=库存放的位置
执行该文件后测试成功,打开MQTTX软件可以发布或者订阅消息: