Qt与MQTT交互通信


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.mzph.cn/bicheng/54104.shtml

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

相关文章

Zabbix自定义监控项与触发器

当我们需要获取某台主机上的数据时,直接利用 zabbix 提供的模板可以很方便的获得需要的数据,但是有些特别的数据,利用这些现有的模板或监控项是无法实现的,例如网站状态信息的监控、mysql数据库主从状态等信息。这是就需要自己定义键值和监控…

【Unity】在Unity 3D中使用Spine开发2D动画

文章目录 内容概括前言下载安装 Spine Pro导入Unity插件Spine动画导入Unity使用展现动画效果展现 内容概括 本文主要讲解 Spine Pro 免(破)费(解)版的安装,以及如何将动画导入到Unity中使用。 前言 通常要用 Spine …

基于鸿蒙API10的RTSP播放器(七:亮度调节功能测试)

目标: 当我的手指在设备左方进行上下移动的时候,可以进行屏幕亮度的调节,在调节的同时,有实时的调节进度条显示 步骤: 界面逻辑:使用Stack() 组件,完成音量图标和进度条的组合显示&#xff0c…

Unity 粒子系统参数说明

一、Particle System 1. Duration(持续时间) 粒子系统运行一次所需的时间。它决定粒子系统持续播放的时间长度。 2. Looping(循环播放) 如果启用,粒子系统将在播放完一次后自动重新开始播放,直到你停止它…

3. 进阶指南:自定义 Prompt 提升大模型解题能力

怎么判断 Prompt 的好坏,有什么问题有着标准答案么? 答:让大模型求解数学问题。 李宏毅老师的 HW4 正好提到了有关数学问题的 Prompt,所以我决定中间插一篇这样的文章。通过本文你将: 了解各种 Prompt 如何影响大型语言…

javase复习day22泛型、set、数据结构

泛型 package MyGenerics;import java.util.ArrayList; import java.util.Iterator;public class GenericsTest1 {public static void main(String[] args) {//没有泛型的情况ArrayList list new ArrayList();//所有数据都被认为是Object类型,都可以加入集合中list…

记录开发一个英语听力训练网站

背景 在当前全球经济衰退的背景下,IT相关的工作在国内的竞争也是越来越激烈,为了能够获得更多的可能性,英语的学习也许能为程序员打开一扇新的窗户,比如很多远程的工作尤其是国际化背景的工作团队,英语的协作沟通是必…

uniapp 发布苹果IOS详细流程,包括苹果开发者公司账号申请、IOS证书、.p12证书文件等

记录一下uniapp发布苹果IOS的流程。 一、苹果开发者公司账号申请 1、邓白氏编码申请(先申请公司邓白氏编码,这一步需要1-2周,没有这个编码苹果开发者没法申请,已有编码的跳过此步骤): 1)联系苹…

[机器学习]决策树

1 决策树简介 2 信息熵 3 ID3决策树 3.1 决策树构建流程 3.2 决策树案例 4 C4.5决策树 5 CART决策树(分类&回归) 6 泰坦尼克号生存预测案例 import pandas as pd from sklearn.model_selection import train_test_split from sklearn.tree import …

链表的快速排序(C/C++实现)

一、前言 大家在做需要排名的项目的时候,需要把各种数据从高到低排序。如果用的快速排序的话,处理数组是十分简单的。因为数组的存储空间的连续的,可以通过下标就可以简单的实现。但如果是链表的话,内存地址是随机分配的&#xf…

【H2O2|全栈】关于CSS(2)CSS基础(二)

目录 CSS基础知识 前言 准备工作 选择器的组合 盒模型 示例网页代码 后代选择器 亲代选择器 相邻兄弟选择器 后续兄弟选择器 多个元素选择器 通配符选择器 优先级 其他应用 伪类 锚链接的属性 列表的属性 list-style-type list-style-position list-style…

react 事件处理

概述 Web应用中,事件处理是重要的一环,事件处理将用户的操作行为转换为相应的逻辑执行或界面更新。在React中,处理事件响应的方式有多种,本文将详细介绍每一种处理方式的用法、使用场景和优缺点。 如果原生DOM有一个监听事件&…

QGis二次开发 —— 3、程序加载栅格tif与矢量shp文件可进行切换控制,可进行导出/导入工程(附源码)

效果 功能说明 软件可同时加载.tif栅格图片与.shp矢量图片、加载图片后可进行自由切换查看图层、可对加载的图片进行关闭 关闭后清空图层、可对加载的图片进行导出.qgs的QGIS工程、可对.qgs的QGis工程导入并导入后可进行自由切换查看图层。 源码 注意: 在加载tif栅格文件后会在…

el-table 如何实现行列转置?

在某些需求里需要用到 行列转置 的表格,但 el-table 提供的基本表格是不支持行列转置的,这样就需要对这个表格进行二次开发。下面来看具体实现的效果: 具体实现方式 基本原理就是对原有的可渲染的数据结构进行处理,表头与表格数…

计算机的错误计算(九十三)

摘要 探讨 log(y,x) 即以 x 为底 y 的对数的计算精度问题。 Log(y,x)运算是指 x 为底 y 的对数。 例1. 计算 log(123667.888, 0.999999999999999) . 不妨在Python中计算,则有: 若在 Excel 单元格中计算,则有几乎同样的输出: 然…

模型部署基础

神经网络的模型部署是将训练好的神经网络模型应用到实际系统中,以实现预测、分类、推荐等任务的过程。下图展示了模型从训练到部署的整个流程: 1.模型部署的平台 在线服务器端部署 在线服务器端部署适用于处理大模型、需要精度优先的应用场景&#xff…

CSCC2024数据库内核赛道Profile记录

同学参加CSCC2024数据库系统赛道比赛,我和他一起研究了一些优化的case,最后成功拿到全国2/325。在这里记录一下我们讨论优化过的问题(建议把源码下下来边读边搜代码,否则会晕) 行锁占用内存过大 Q:TPCC测…

OpenCV运动分析和目标跟踪(1)累积操作函数accumulate()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将一个图像添加到累积图像中。 该函数将 src 或其部分元素添加到 dst 中: dst ( x , y ) ← dst ( x , y ) src ( x , y ) if mask…

网络基础,协议,OSI分层,TCP/IP模型

网络的产生是数据交流的必然趋势,计算机之间的独立的个体,想要进行数据交互,一开始是使用磁盘进行数据拷贝,可是这样的数据拷贝效率很低,于是网络交互便出现了; 1.网络是什么 网络,顾名思义是…

串口接收不到数据之电阻虚焊bug分析思路

单片机和EC移远通信模块进行通信,相同的代码运行在相同的硬件上,但是一个能联网,一个因为没有EC的应答连不上网。 开始分析,排除软件问题,给EC模块发为什么没应答? 1.发送失败 2.接收失败 排除情况2&#x…