科百科
当前位置: 首页 范文大全

mqtt的三种qos级别(彻底搞懂Qt-MQTT开发)

时间:2023-07-20 作者: 小编 阅读量: 4 栏目名: 范文大全

消息队列相关的通信协议都属于应用层协议,位于OSI模型第七层,是基于TCP/IP的通信协议。与TCP、UDP或是HTTP协议不同,MQ相关协议没有服务端和客户端的概念。如降低系统可用性,增加系统的复杂性和一致性问题等。因此,是否使用消息队列也必须根据实际应用来决定。输入初始用户名admin和用户密码public,即可进入控制面板,并进行MQTT服务器相关配置。

消息队列

“消息队列(MQ)”是在消息的传输过程中保存消息的容器。

消息队列正如同一种先进先出的队列结构,它将发送方的消息推入队列中,并依序推送给接收方。消息队列相关的通信协议都属于应用层协议,位于OSI模型第七层,是基于TCP/IP的通信协议。

与TCP、UDP或是HTTP协议不同,MQ相关协议没有服务端和客户端的概念。原本的客户端和服务端,现在都通过一个中间件服务器(broker)交互,消息的发送方称为生产者,消息的接收方成为消费者,生产者和消费者都可以视同broker的客户端。

通过这种设计,所有消息都被存放于一个中间服务器中,通信的双方不再需要创建服务。这样做带来了几个好处:解耦,异步调用,削峰。

解耦:通过中间件,各个系统之间可以独立运行,不会因为其中一个系统的崩溃影响其他系统,且整个系统的可拓展性也大大加强。

异步:发送方的消息推入了中间件,这条消息可以被所有相关的接收方看到,因此它们可以同时开始处理,这种串联的结构的时间消耗比其他的串行结构小得多。

削峰:在高并发环境下,短时间的大量请求会导致系统和数据库发生很多问题,所以需要对流量进行控制,通过消息队列设置每秒向消费者投递的消息数量,可以控制并发环境下的系统稳定性。

但是,消息队列同样有它的不足。如降低系统可用性,增加系统的复杂性和一致性问题等。因此,是否使用消息队列也必须根据实际应用来决定。

基于消息队列的通信协议有很多,常见的有RabbitMQ,Kafka,还有本文介绍的MQTT。

【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】

点击→领取「链接」

MQTT

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。

MQTT会构建底层网络传输:它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输。当应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连。

MQTT中的几个重要概念:

订阅(Subscription)

订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。

会话(Session)

每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。

主题名(Topic Name)

连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。服务器会将消息发送给订阅所匹配标签的每个客户端。

主题筛选器(Topic Filter)

一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。

负载(Payload)

消息订阅者所具体接收的内容。

【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】

点击→领取「链接」

配置Qt-MQTT环境

默认的Qt环境是不能使用MQTT的,但Qt官方提供了基于MQTT的封装,需要通过源码进行编译。

在dev分支中可以选择MQTT版本,选择最新的下载到本地。

下载下来的是一个Qt项目,在QT Creator中打开.pro文件,然后使用Release模式,用你所需要的编译器(VS,MinGW…),开始编译。

如果你的系统没有安装过Perl,需要先安装Perl,并加入到系统环境变量中。

完成编译后,可以在你的编译路径的/bin目录中得到所需的动态链接库文件Qt5Mqtt.dll和Qt5Mqttd.dll。前者是release版库,后者是debug版。

为了实现一次配置,所有项目可用的目的,我们可以直接将MQTT配置到系统的Qt环境中去。C的编译机制是通过头文件和静态链接库编译出动态链接库,再通过头文件和动态链接库运行程序。所以这里我们要将前面编译出的静态链接库和动态链接库都复制到Qt环境中去。

首先,将qtmqtt源码目录下(qtmqtt/src/mqtt)的所有.h头文件拷贝,在Qt安装目录下的include文件夹中创建一个mqtt目录,将拷贝的文件粘贴进去。

然后,将源码编译生成目录下的静态链接库相关文件拷贝到Qt安装目录的/lib下,

依次为Qt5Mqtt.lib(.a) Qt5Mqtt.prl Qt5mqttd.lib(.a) Qt5Mqttd.prl。

再将编译生成的两个动态链接库拷贝到Qt安装目录的/bin下,

依次为Qt5Mqtt.dll Qt5Mqttd.dll。

最后再拷贝模块配置文件到Qt安装目录中。

这样MQTT就已经配置到我们本地的Qt环境中了。后续所有使用此Qt环境的项目都可以直接使用MQTT了。

使用MQTT时,首先要在.pro中添加模块:

QT= mqtt

在使用前引入包:

#include <QtMqtt/qmqttClient.h>

编写代码可以参考Qt官方的MQTT说明文档:

https://doc.qt.io/qt-6/qtmqtt-index.html

搭建EMQ X服务器

为了调试程序,我们需要一台MQTT服务器。EMQ公司官方提供了测试的MQTT服务器,但由于连接数众多,不太稳定,我们需要自己搭建一台MQTT服务器。

EMQ X提供了开源版的EMQ X服务器安装包,支持Windows,Ubuntu等多种使用环境。

安装后,Windows用户使用管理员权限命令行进入安装路径下,进入/emqx/bin/,依次执行命令

#先运行该命令emqx install#成功后界面上会ChangeServiceConfig 成功#再运行emqx console#运行成功后会显示emqx is started!#然后会跳出一个界面,打开emqx运行所需要的各个端口#最后运行emqx start#没有报错就执行成功了

Linux用户在安装路径下执行下述命令即可

emqx start

这样本地就开启了MQTT服务,这里有两个重要的端口号要记住:1883(暴露给外部的MQTT服务端口),18083(服务器控制面板端口)。在本地浏览器输入http://127.0.0.1:18083/,打开服务器控制面板。输入初始用户名admin和用户密码public,即可进入控制面板,并进行MQTT服务器相关配置。

【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】

点击→领取「链接」

调试软件MQTT X

为了调试程序,我们通常需要一个调试软件来模拟消息的收发,这里推荐使用MQTT X软件进行调试。

MQTT X下载连接:https://mqttx.app/zh

MQTT X使用文档:https://mqttx.app/zh/docs

安装完成后,点击 图标可以添加连接。

这里的Name和Client ID随意,Host填写我们本地配置的MQTT服务器地址127.0.0.1,端口号填1883。点击Connect即可连接到本地。

连接后,点击New Subscription创建topic,然后就可以在该topic下收发消息。

Qt-MQTT编程

这里给出一个Qt-MQTT的程序样例,包含了基础的连接,收,发,断开等功能,读者可以在此基础上二次开发。

.h

#ifndef MY_MQTT_CLIENT_H#define MY_MQTT_CLIENT_H#include <QObject>#include <QDateTime>#include <QtMqtt/qmqttclient.h>namespace Ui {class MyMQTTClient;}using namespace std;class MyMQTTClient : public QObject{Q_OBJECTpublic:explicit MyMQTTClient(QObject *parent = nullptr);~MyMQTTClient(){};QMqttClient *m_client = nullptr;void MyMQTTSubscribe(QString);void MyMQTTSendMessage(const QString, const QString);SIGNALs:public slots:void brokerConnected();void updateLogStateChange();void brokerDisconnected();void receiveMess(const QByteArray &, const QMqttTopicName &);private:};#endif // MY_MQTT_CLIENT_H

.cpp

#include "my_mqtt_client.h"MyMQTTClient::MyMQTTClient(QObject *parent) : QObject(parent){m_client = new QMqttClient(this);m_client->setHostname("127.0.0.1");m_client->setPort(1883);m_client->connectToHost();connect(m_client, &QMqttClient::connected, this, &MyMQTTClient::brokerConnected);connect(m_client, &QMqttClient::stateChanged, this, &MyMQTTClient::updateLogStateChange);connect(m_client, &QMqttClient::disconnected, this, &MyMQTTClient::brokerDisconnected);connect(m_client, &QMqttClient::pingResponseReceived, this, [this]() {const QString content = QDateTime::currentDateTime().toString()QLatin1String(" PingResponse")QLatin1Char('\n');qDebug() << content;});}void MyMQTTClient::MyMQTTSubscribe(QString str){auto subscription = m_client->subscribe(str, 0);if (!subscription) {qDebug() << "Could not subscribe. Is there a valid connection?";return;}}void MyMQTTClient::updateLogStateChange(){const QString content = QDateTime::currentDateTime().toString()QLatin1String(": State Change")QString::number(m_client->state())QLatin1Char('\n');qDebug() << content;}void MyMQTTClient::brokerConnected(){qDebug() << "Connected!";if(m_client->state() == QMqttClient::Connected){m_client->subscribe(QString(MQTT_AUTO_TOPIC), 0);connect(m_client, SIGNAL(messageReceived(QByteArray,QMqttTopicName)), this, SLOT(receiveMess(QByteArray,QMqttTopicName)));}}void MyMQTTClient::brokerDisconnected(){qDebug() << "Disconnected!";}void MyMQTTClient::receiveMess(const QByteArray &message, const QMqttTopicName &topic){QString content;content = QDateTime::currentDateTime().toString()QLatin1Char('\n');content= QLatin1String(" Received Topic: ")topic.name()QLatin1Char('\n');content= QLatin1String(" Message: ")messageQLatin1Char('\n');qDebug() << content;}void MyMQTTClient::MyMQTTSendMessage(const QString topic, const QString message){if (m_client->publish(topic, message.toUtf8()) == -1){qDebug() << "Could not publish message";}}

    推荐阅读
  • 如何快速剥桂圆的皮(桂圆皮怎么剥)

    然后用手指在开口两端往中间稍用力捏。这个开口就会慢慢扩大,这样桂圆壳就很容易与果肉分离开来了。将有曲痕的一面对着自己。然后双手捏住果肉,用力一挤,桂圆壳就会裂开来,这样就能很轻松取出果肉了。

  • 明月是喜欢子秋还是凌霄(明月喜欢凌霄吗)

    在高中的时候,齐明月曾被骗子勒索,被堵在街头,因为贺子秋的见义勇为令齐明月暗生情愫,她甚至把喜欢表现得很明显。齐明月会找机会让尖尖约两个哥哥一起相处,会和他们一起做作业,在贺子秋生日时送上手表,还时刻关注他的动态。但在九年后,当贺子秋和凌霄在国外学成归来,齐明月竟对凌霄的事格外上心,不仅是第一个知道他回家的人,去机场接他,还提前安排好了住处。

  • 鳜鱼苗的养殖方法(鳜鱼苗的人工养殖方法)

    还有就是鳜鱼苗看上去要比较干净,没有伤痕,这样就差不多啦。饲料管理鳜鱼它主要是以捕捉水中的小鱼小虾喂食,其次再是水中的浮游生物,最后再是一些按照配方配好的饲料。

  • 肖燕个人资料简介(肖燕个人资料有什么)

    肖燕个人资料简介肖燕,1997年3月6日出生,中国内地女演员。2015年,参演悬疑轻喜剧《煮妇神探》从而开启演艺道路。2016年10月26日,校园喜剧电影《公主和她的49个男仆》上线,在片中饰演女主角苏闯。2018年,主演由郭靖宇担任总导演及监制的年代传奇剧《小娘惹》。2020年3月,主演的民国悬疑剧《民国奇探》播出。2020年6月,主演的女性励志传奇电视剧《小娘惹》播出。

  • 塞尔达传说野之息全料理食材及效果介绍 有哪些食谱?

    塞尔达传说荒野之息游戏中料理配方有不少,大家可也任意选择,这里给大家带来了塞尔达传说野之息全料理食材及效果介绍,一起来看下都有哪些食谱吧。全料理食材及效果介绍

  • 黑龙江30多名女学生街头约架斗殴 黑龙江30多名女学生街头约架斗殴|少

    由于这两天黑龙江30多名女学生街头约架斗殴在网上的关注热度是相当之高的,很多小伙伴或许也都在关注黑龙江30多名女学生街头约架斗殴,那么这当中当然还是有部分的小伙伴们并不太了解黑龙江30多名女学生街头约架斗殴,那么没有关系,如果说大家现在想要了解黑龙江30多名女学生街头约架斗殴,大家可以点击下方的点击(前往)进行了解哦。

  • 科三全程考试项目及过程(科三全考点总结)

    打开车门前需观察后方交通情况。直线行驶:进入直线行驶前,先换至三挡,已每小时30公里幅度行驶,直线行驶时注意不跑偏,保持适当跟车距离,适时通过内、外后视镜观察交通情况,视线离开不高于2秒。确认安全后,驶入左侧车道,鸣笛或交替使用远近光灯提醒,保持与被超车车辆安全距离后加速超越。超越后,打右转向灯,通过内外后视镜观察,确认安全后驶回原车道。会车:会车前,提前刹车减速至30公里/小时以内。

  • 合肥经开区免费办健康证需要什么条件?

    合肥经开区免费健康证办理需要什么条件经开区高刘社区卫生服务中心:条件:经开区户籍或者经开区从业人员锦绣社区卫生服务中心:条件:经开区户籍或者经开区从业人员,家庭医生签约后赠送健康证,交20元家庭医生有偿签约费临湖社区卫生服务中心:条件:经开区居民或在经开区从事(食品,药品,化妆品,饮用水,公众场所相关从业人员)合肥经开区免费健康证办理点分布经开区高刘社区卫生服务中心:高刘栗树路与富蕴路交口锦绣社区

  • 野外遇老虎如何自救(女子下班途中路遇东北虎)

    经常出入“老虎森林”应随身携带驱虎工具,世界野生动物保护学会和东北虎豹国家公园推荐的驱虎工具是火焰信号弹。一旦老虎决定发起攻击,赤手空拳的人将很难生还。发现受伤致残、年老体弱或频繁出入村庄的老虎,或者其他对人类有潜在威胁的老虎,要及时报告林草部门,由他们进行妥善处置。据保守估计,截至2016年底,吉林省已有东北虎27只,东北豹42只。

  • 蔚来es7实车颜色(新车蔚来ES7正式上市)

    新车基于NT2平台打造,在智能化方面与ET7看齐,并且该车也将会销往全球,并采用全球统一定价策略。在发布会上,蔚来官方宣布ES7的补贴前售价为46.8万元起,新车在8月28日即可开启交付。前排主驾坐垫可延长60毫米,副驾标配女王副驾后排靠背可支持8度调节ES7的座椅造型和ET7相同,并且舒适度得到优化。另外,蔚来ES7也是国内首批通过法规认证,可以合法拖挂房车、挂车上路的乘用车。