Qt与MQTT交互通信

news2024/11/24 6:45:26


MQTT全称是(Message Queuing Telemetry Transport),即消息队列遥测传输协议

是一种基于发布/订阅(Publish/Subscribe)模式的轻量级通讯协议,并且该协议构建于TCP/IP协议之上,常用于互联网中,轻便

基本组件

  1. 客户端(Client)

    • 任何设备(传感器、手机、应用程序等)都可以作为MQTT客户端。
    • 客户端可以发布消息(Publisher)或者订阅消息(Subscriber)。
  2. 代理(Broker)

    • 代理是MQTT网络的核心组件,负责接收来自发布者的消息并将其转发给订阅了该主题的客户端。
    • 它确保消息的传递和分发,管理客户端连接、订阅、注销等操作。

工作流程

  1. 连接

    • MQTT客户端通过TCP/IP与MQTT代理建立连接。连接建立后,客户端必须发送“连接”请求。
    • 代理根据请求的信息(如客户端ID、用户名、密码等)进行身份验证和授权。
  2. 发布(Publish)

    • 客户端将消息发布到特定的主题(Topic)。主题是一种类似路径的层级结构,可以用斜杠(/)分隔,如 sensors/temperature/kitchen
    • 代理接收消息并进行处理。
  3. 订阅(Subscribe)

    • 客户端可以订阅一个或多个主题。订阅后,代理会将所有属于该主题的消息分发给相应的客户端。
    • 订阅可以是精确的主题,也可以包含通配符来匹配多个主题。
  4. 消息分发

    • 代理将发布的消息转发给所有订阅了该主题的客户端。
  5. 断开连接

    • 客户端可以随时断开与代理的连接。代理也可以在检测到长时间未活动后断开客户端连接。

应用场景

MQTT广泛应用于物联网、车联网、智能家居、远程监控和消息推送等场景。其轻量级、低带宽、高效的特性使其特别适合资源受限及网络不稳定的环境。

通过这些组件和操作,MQTT可以实现高效、可靠的消息传递,成为物联网通信中的重要协议。

QT 交互例子

准备工作:MQTT客户端的交互需要安装MQTT代理,及代理服务器,负责将消息转发。按照好后配置相关,如监听的端口和协议、是否启用消息持久化、日志文件路径等。根据需求修改这些设置,保存配置文件等。这里就不赘述

接下来详细讲解在QT中MQTT的使用:

1.使用官方的MQTT源码,造好的轮子有用就用,官网:https://github.com/emqx/qmqtt

或者这个链接下载: https://pan.baidu.com/s/1oUtl9R628-3cfS-tyL6iEQ?pwd=1234 提取码: 1234 

下载完解压:放到程序目录下

我的例子程序结构如下,分为mqtt封装的库,用于发送接收消息,和界面主程序用于控制发送和消息显示

2.写一个例子,这里给关键代码展示

一是连接mqtt,二是推送消息函数,三是接收订阅的消息函数

void MqttShareHandle::initMqtt()
{
    if (client) {
        return;
    }
    client.reset(new QMqttClient);
    QObject::connect(client.get(), &QMqttClient::connected, this, &MqttShareHandle::connected);
    QObject::connect(client.get(), &QMqttClient::disconnected, this, &MqttShareHandle::disconnected);
    QObject::connect(client.get(), &QMqttClient::errorChanged, this, &MqttShareHandle::errorChanged);
    QObject::connect(client.get(), &QMqttClient::messageReceived, this,
                     [=](const QByteArray &message, const QMqttTopicName &topic) {
                         emit messageReceived(message, topic.name());
                     });
    QObject::connect(client.get(), &QMqttClient::messageReceived, this,
                     [=](const QByteArray &message, const QMqttTopicName &topic) {
                         onMessageReceived(message, topic.name());
                     });
}

void MqttShareHandle::connectToHost(const QString &host,
                                       quint16 port,
                                       const QString &username,
                                       const QString &password)
{
    if (!client || isConnected()) {
        return;
    }

    client->setHostname(host);
    client->setPort(port);
    client->setUsername(username);
    client->setPassword(password);
    client->connectToHost();
}
//订阅消息
void MqttShareHandle::subscribeBizTopics()
{
    //保证消息至少到达一次。
    //较为可靠,适用于大多数需要保证消息到达的场景
    const quint8 qos = 1;
    subscribeTopic(TopicAppEnvData, qos);
    subscribeTopic(TopicAppDeviceStatus, qos);
    subscribeTopic(TopicAppEventNotify, qos);
}

bool MqttShareHandle::subscribeTopic(const QString &topic, quint8 qos)
{
    if (!client) {
        return false;
    }

    auto subscription = client->subscribe(topic, qos);
    return subscription ? subscription->state() == QMqttSubscription::Subscribed : false;
}

//推送消息
bool MqttShareHandle::publishTopic(const QString &topic, const QByteArray &data, quint8 qos, bool retain)
{
    if (!client) {
        return false;
    }
    emit printMsg(QString("推送消息, topic:%1,data:%2").arg(topic).arg(QString(data)));
    auto ret = client->publish(topic, data, qos, retain);
    return ret != -1;
}

void MqttShareHandle::onMessageReceived(const QByteArray &message, const QString &topic)
{
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(message, &error);
    if (error.error != QJsonParseError::NoError) {
        return;
    }
    //QMetaObject::invokeMethod(this, MessageMap.value(topic).toUtf8(), Q_ARG(QByteArray,message));
    emit printMsg(QString("收到消息推送, topic:%1,data:%2").arg(topic).arg(QString(message)));

    if(topic == TopicAppEnvData) {
        emit appEnvDataUpdate(message);
    }
    else if(topic == TopicAppEventNotify) {
        emit appEventNotify(message);
    }
    else if(topic == TopicAppDeviceStatus) {
        emit appDeviceStatusUpdate(message);
    }
}

我的这个例子用了五个主题要演示推送和接收

// 环境信息更新主题
QString MqttShareHandle::TopicAppEnvData = "/Topic/EnvData";
// 设备状态更新主题
QString MqttShareHandle::TopicAppDeviceStatus = "/Topic/DeviceStatus";
// 事件通知主题
QString MqttShareHandle::TopicAppEventNotify = "/Topic/EventNotify";
//------------------------消息发布(推送)-------------------------
// 控制设备主题
QString MqttShareHandle::TopicControlDevice = "/Topic/ControlDevice";
// 控制门主题(开关门)
QString MqttShareHandle::TopicControlDoor = "/Topic/ControlDoor";

写了一个demo程序,如下,改程序可以通过mqtt推送开关门控制事件,模拟控制订阅“TopicControlDoor”主题的设备控制开关门,控制订阅TopicControlDevice主题的设备控制开关灯,并且订阅相关设备推送消息的主题,便于接收响应的信息

演示下效果,比较简陋,:

我用这个QT客户端模式外部设备

演示视频

通过订阅环境主题,事件,设备状态,可以接收设备的相关消息推送

设备也订阅了控门事件,控灯事件。接收到app的推送后,也显示出来,做出相应的处理


通过这个例子,可以认识到,mqtt的通讯方式是一对多,也可以一对一,实现方式也很简单,订阅与发布。

订阅就相当于你关注了一个人,UP主(uploader),他要是发布了动态或者视频等,就会通知你,如果你没有关注那个人,肯定不会接收到通知

发布就反过来,你是UP主,发布的东西只要他人关注了你,就会被通知

这个例子的源码我就放在这里了,有什么不懂的,欢迎评论区交流哈!

链接: https://pan.baidu.com/s/1v_xViXSHoV2QekwdKDq7SA?pwd=6666 提取码: 6666 

为什么有了tcp通信后,还要有人写一个mqtt出来呢?

mqtt的优势

1. 发布/订阅模式

MQTT 采用发布/订阅模式,允许客户端发布消息到主题(Topic),其他客户端可以订阅这些主题来接收消息。这种模式使得消息的传递更加灵活和解耦,客户端之间不需要直接连接,减少了复杂性。

2. 轻量级

MQTT 协议设计得非常轻量级,适合在带宽有限、网络不稳定的环境中使用,如物联网设备。MQTT 的消息头非常小,最小只有 2 字节,这使得它在低带宽网络中传输效率更高。

3. QoS(服务质量)

MQTT 提供了三种服务质量(QoS)级别:

  • QoS 0:最多一次(At most once),消息发送一次,不保证接收。
  • QoS 1:至少一次(At least once),消息至少发送一次,可能会重复。
  • QoS 2:恰好一次(Exactly once),消息只发送一次,保证不重复。

QoS 0(最多一次,At most once)

特点:

  • 消息传输是尽力而为,不保证消息到达。
  • 不进行消息确认,不做重发。
  • 最低的网络开销和延迟。

使用场合:

  • 传感器数据:如环境温度、湿度等,定期发送,如果丢失一两条数据不会有太大影响。
  • 日志数据:实时性和完整性要求不高的日志信息。
  • 状态更新:如设备的在线状态,定期发送,如果有丢失可在下次更新时弥补。

优点:

  • 最低的网络开销。
  • 最低的延迟。
  • 简单实现。

缺点:

  • 不保证消息到达。
  • 可能会丢失消息。

QoS 1(至少一次,At least once)

特点:

  • 消息至少到达一次。
  • 发送者会重发消息直到收到接收者的确认。
  • 接收者可能会收到重复的消息,需要去重。

使用场合:

  • 重要数据:如报警信息,需要确保接收者至少收到一次,即使可能会有重复。
  • 财务记录:如银行交易,需要确保消息到达,但可以接受重复处理。
  • 设备控制:如远程设备控制命令,需要确保命令被接收和执行,但可以手动处理重复执行。

优点:

  • 保证消息至少到达一次。
  • 较为可靠,适用于大多数需要保证消息到达的场景。

缺点:

  • 可能会收到重复消息,需要处理冗余。
  • 网络开销和延迟高于 QoS 0。

QoS 2(只有一次,Exactly once)

特点:

  • 消息保证到达且仅到达一次。
  • 通过四次消息交换确保消息的唯一性和可靠性。
  • 最高的可靠性,适合对传输可靠性要求极高的场合。

使用场合:

  • 关键指令:如关键操作的执行命令,不能出现丢失或重复的情况。
  • 交易处理:如金融交易,需要严格的消息确保机制,要求高可靠性。
  • 数据同步:如重要数据库的同步操作,需要确保数据准确性和一致性。

优点:

  • 保证消息仅到达一次。
  • 最高的传输可靠性。

缺点:

  • 最高的网络开销。
  • 延迟较高,因为需要多次消息交换。
  • 实现复杂。

这些 QoS 级别使得 MQTT 能够适应不同的应用场景,确保消息的可靠传输。

4. 会话保持

MQTT 支持会话保持(Session Persistence),即使在客户端断开连接后,服务器仍然可以保存客户端的订阅信息和未接收的消息,当客户端重新连接时,可以继续接收这些消息。

5. 遗嘱消息(Last Will and Testament)

MQTT 支持遗嘱消息(LWT),客户端可以在连接时设置一个遗嘱消息,当客户端异常断开连接时,服务器会自动发布这个遗嘱消息,通知其他客户端该客户端已经断开连接。

6. 心跳机制

MQTT 支持心跳机制(Keep Alive),客户端可以定期发送 PING 请求,确保连接的活跃性,服务器也可以通过 PING 响应来检测客户端的连接状态。

7. 安全性

MQTT 支持 TLS/SSL 加密,确保消息在传输过程中的安全性。此外,MQTT 还支持用户名和密码认证,增加了系统的安全性。

8. 易于扩展

MQTT 的发布/订阅模式和主题(Topic)结构使得系统易于扩展。新的客户端可以轻松地加入系统,订阅感兴趣的主题,而不需要修改现有的客户端或服务器。

9. 广泛支持

MQTT 协议得到了广泛的支持,有大量的客户端库和服务器实现,适用于各种编程语言和平台,如 C、C++、Java、Python、JavaScript 等。

总结

相比于直接使用 TCP,MQTT 提供了更高层次的抽象和功能,使得消息的传递更加灵活、可靠和高效。特别是在物联网和低带宽网络环境中,MQTT 的优势更加明显。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2125432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3封装数字上下滚动翻牌器,

优点&#xff1a;可以传入字符串设置初始数字位数&#xff0c;也可以直接传入数字&#xff0c;让他自己根据位数渲染 组件代码&#xff1a; <template><div class"count-flop" :key"compKey"><!-- --><div:class"item ! . ?…

【EI会议征稿通知】第四届材料工程与应用力学国际学术会议(ICMEAAE 2025)

第四届材料工程与应用力学国际学术会议&#xff08;ICMEAAE 2025&#xff09; 2025 4th International Conference on Materials Engineering and Applied Mechanics 本次会议将重点讨论材料科学、应用力学等领域的最新研究进展与发展趋势。会议旨在为国内外从事这些领域研究…

怎么利用接口发送图文彩信

在数字化时代&#xff0c;信息的传递方式日新月异&#xff0c;从传统的书信、电话到如今的即时通讯软件、社交媒体&#xff0c;每一种新技术的应用都在不断重塑我们的沟通方式。而在这其中&#xff0c;彩信&#xff08;Multimedia Messaging Service, MMS&#xff09;作为一种融…

python安装tensorflow一直报错

python安装tensorflow一直报错&#xff0c;试了3.5、3.6、3.7、3.8、3.9、3.10&#xff0c;人麻&#xff0c;全部都不行 问题描述 pip install tensorflow报错ERROR: Could not find a version that satisfies the requirement tensorflow (f问题分析 直到在网上看到&#x…

体系结构论文导读(四十五):Design and Dynamic Update of Real-Time Systems 19‘RTSS

挑战部分 背景问题&#xff1a; 现代工业系统和产品&#xff08;如汽车、智能手机、医疗设备&#xff09;越来越依赖于软件&#xff0c;尤其是嵌入式实时系统。这些系统的可靠性对于社会至关重要&#xff0c;比如特斯拉自动驾驶系统的软件问题曾引发一些事故。目前&#xff0c;…

二维码生成

1、引入二维码生成库 使用一个支持二维码生成的库&#xff0c;如ZXing&#xff08;Zebra Crossing&#xff09;&#xff0c;它提供了二维码生成的工具和API。 pom.xml文件导入ZXing依赖。 <!-- ZXing 库依赖 --><dependency><groupId>com.google.zxing<…

OpenSNN推文:《从沙粒到超级大脑:一步步揭开芯片的秘密》

你有没有想过&#xff0c;手机、电脑、电视等设备里的“智能大脑”是怎么来的&#xff1f;这个大脑就是芯片&#xff0c;它让这些设备变得聪明&#xff0c;能够快速处理各种信息。今天&#xff0c;我将详细地解释芯片的诞生过程&#xff0c;从最基础的原材料一直到它成为我们日…

【HCIA-Datacom】数据通信网络基础

数据通信网络基础 1. 通信与网络网络通信的基本概念数据通信网络定义网络设备 2. 网络类型与网络拓扑网络类型网络拓扑网络拓扑形态 3.网络工程与网络工程师的定义测一测 1. 通信与网络 这里只用作简单的了解即可&#xff0c;在后续中 网络通信的基本概念 ⭐通信&#xff1…

总结——薄基础_Android开发_简易计算器__非教程

关于初学Android开发一段时间的总结&#xff0c;并非教程。主要是为自己防呆&#xff0c;避免以后学习新知识时走一遍老路。再次强调并非教程&#xff0c;如有不妥之处还望见谅 零基础学习比较庞大的内容是十分吃力不讨好的&#xff0c;建议此前至少学习相关编程知识。此谓“薄…

从0到1教你搭建Android自动化Python+appium环境

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、需要软件 1. JDK:JAVA安装后配置JDK环境 2. SDK:SDK下载后配置adb环境 3. Python:pyhton语言 4. Pycharm:python脚本编译工具 5. Appium-python-clie…

CCF推荐B类会议和期刊总结:(计算机网络领域)

CCF推荐B类会议和期刊总结&#xff08;计算机网络领域&#xff09; 在计算机网络领域&#xff0c;中国计算机学会&#xff08;CCF&#xff09;推荐的B类会议和期刊代表了该领域的较高水平。以下是对所有B类会议和期刊的总结&#xff0c;包括全称、出版社、dblp文献网址以及所属…

QML与widget

杂谈 QML-各类建材&#xff08;水泥、沙石、钢筋等各种材料&#xff09;&#xff0c;可以做出各种炫酷建筑wiget-板房&#xff0c;可靠、功能性强。 QML&#xff08;Qt Meta Language or Qt Modeling Language&#xff09;&#xff1a; QML 是一种基于 JavaScript 的声明式语…

‌汽车一键式启动系统‌包含哪些功能

‌汽车一键式启动系统‌是一种智能化的汽车启动系统&#xff0c;它通过一个按钮来启动和熄灭发动机&#xff0c;取代了传统的钥匙启动方式。这个系统不仅简化了启动和熄火的步骤&#xff0c;还提供了多种智能化的功能&#xff0c;如自动开锁、自动关锁、自动关窗、自动防盗等。…

HarmonyOS开发之(下拉刷新,上拉加载)控件pulltorefresh组件的使用

效果图&#xff1a; 一&#xff1a;下载安装&#xff08;地址&#xff1a;OpenHarmony-SIG/PullToRefresh&#xff09; ohpm install ohos/pulltorefresh 二&#xff1a;使用lazyForEarch的数据作为数据源 export class BasicDataSource implements IDataSource{private l…

一种简易CAN数据分析器的实现(一)【工程创建+CAN波特率计算工具】

程序实现详见《一种简易CAN数据分析器的实现&#xff08;二&#xff09;【程序实现】》 微信公众号关注&#xff1a;掌芯元器&#xff0c;免费为大家提供嵌入式相关的技术咨询&#xff01;&#xff01;&#xff01; 目录 一、功能需求及实现 1、功能设计及实现 2、软硬件需求…

视频怎么转换成mp3格式?分享5种便捷的转换方法

在日常生活中&#xff0c;我们经常会遇到需要将视频文件中的音频提取出来&#xff0c;转换成MP3格式的情况&#xff0c;以便在手机、MP3播放器或其他设备上播放。今天&#xff0c;我将为大家介绍5种视频转MP3的方法&#xff0c;非常简单便捷&#xff0c;一起来学习下吧。 方法一…

oelove奥壹婚恋征婚相亲交友系统v10.0原生小程序源码(无编译加密)上架经验让你少走弯路

首先大家要明白什么是原生小程序&#xff01;以微信小程序为例&#xff0c;原生小程序就是指在微信指定的平台“开发者工具”按照平台规则开发出来的小程序才是原生小程序&#xff0c;像uniapp它就不属于原生小程序是第三方&#xff0c;原生小程序的好处那一万字也说不完&#…

JavaScript第五天(函数,this,严格模式,高阶函数,闭包,递归,正则,ES6)高级

这里写目录标题 JavaScript高级第03天1.函数的定义和调用1.1函数的定义方式1.2函数的调用 2.this2.1函数内部的this指向2.2改变函数内部 this 指向2.2.1 call方法2.2.2 apply方法2.2.3 bind方法2.2.4 call、apply、bind三者的异同 3.严格模式3.1什么是严格模式3.2开启严格模式3…

21. Revit API: 几何对象(二)- Curve

上篇讲了Revit几何对象的类层次结构&#xff0c;讲了几何元素和几何实例&#xff0c;简单提到了Solid。 这一篇呢&#xff0c;就从构成Solid的边讲起。 一、Edge&#xff08;边&#xff09; Edge在Revit中就是用来表示边的&#xff0c;并且在各种表示几何结构的类中串门。 前…

使用 Elementary 实现开源数据可观测性 — 从零到精通(第一部分)

欢迎来到雲闪世界。我希望在我还是初学者时能有一份循序渐进的实践指南 数据可观测性及其重要性经常被讨论和撰写为现代数据和分析工程的一个重要方面。市场上有许多工具&#xff0c;具有各种功能和价格。在这篇由两部分组成的文章中&#xff0c;我们将重点介绍 Elementary 的…