• 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,二是推送消息函数,三是接收订阅的消息函数

    1. void MqttShareHandle::initMqtt()
    2. {
    3. if (client) {
    4. return;
    5. }
    6. client.reset(new QMqttClient);
    7. QObject::connect(client.get(), &QMqttClient::connected, this, &MqttShareHandle::connected);
    8. QObject::connect(client.get(), &QMqttClient::disconnected, this, &MqttShareHandle::disconnected);
    9. QObject::connect(client.get(), &QMqttClient::errorChanged, this, &MqttShareHandle::errorChanged);
    10. QObject::connect(client.get(), &QMqttClient::messageReceived, this,
    11. [=](const QByteArray &message, const QMqttTopicName &topic) {
    12. emit messageReceived(message, topic.name());
    13. });
    14. QObject::connect(client.get(), &QMqttClient::messageReceived, this,
    15. [=](const QByteArray &message, const QMqttTopicName &topic) {
    16. onMessageReceived(message, topic.name());
    17. });
    18. }
    19. void MqttShareHandle::connectToHost(const QString &host,
    20. quint16 port,
    21. const QString &username,
    22. const QString &password)
    23. {
    24. if (!client || isConnected()) {
    25. return;
    26. }
    27. client->setHostname(host);
    28. client->setPort(port);
    29. client->setUsername(username);
    30. client->setPassword(password);
    31. client->connectToHost();
    32. }
    33. //订阅消息
    34. void MqttShareHandle::subscribeBizTopics()
    35. {
    36. //保证消息至少到达一次。
    37. //较为可靠,适用于大多数需要保证消息到达的场景
    38. const quint8 qos = 1;
    39. subscribeTopic(TopicAppEnvData, qos);
    40. subscribeTopic(TopicAppDeviceStatus, qos);
    41. subscribeTopic(TopicAppEventNotify, qos);
    42. }
    43. bool MqttShareHandle::subscribeTopic(const QString &topic, quint8 qos)
    44. {
    45. if (!client) {
    46. return false;
    47. }
    48. auto subscription = client->subscribe(topic, qos);
    49. return subscription ? subscription->state() == QMqttSubscription::Subscribed : false;
    50. }
    51. //推送消息
    52. bool MqttShareHandle::publishTopic(const QString &topic, const QByteArray &data, quint8 qos, bool retain)
    53. {
    54. if (!client) {
    55. return false;
    56. }
    57. emit printMsg(QString("推送消息, topic:%1,data:%2").arg(topic).arg(QString(data)));
    58. auto ret = client->publish(topic, data, qos, retain);
    59. return ret != -1;
    60. }
    61. void MqttShareHandle::onMessageReceived(const QByteArray &message, const QString &topic)
    62. {
    63. QJsonParseError error;
    64. QJsonDocument doc = QJsonDocument::fromJson(message, &error);
    65. if (error.error != QJsonParseError::NoError) {
    66. return;
    67. }
    68. //QMetaObject::invokeMethod(this, MessageMap.value(topic).toUtf8(), Q_ARG(QByteArray,message));
    69. emit printMsg(QString("收到消息推送, topic:%1,data:%2").arg(topic).arg(QString(message)));
    70. if(topic == TopicAppEnvData) {
    71. emit appEnvDataUpdate(message);
    72. }
    73. else if(topic == TopicAppEventNotify) {
    74. emit appEventNotify(message);
    75. }
    76. else if(topic == TopicAppDeviceStatus) {
    77. emit appDeviceStatusUpdate(message);
    78. }
    79. }

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

    1. // 环境信息更新主题
    2. QString MqttShareHandle::TopicAppEnvData = "/Topic/EnvData";
    3. // 设备状态更新主题
    4. QString MqttShareHandle::TopicAppDeviceStatus = "/Topic/DeviceStatus";
    5. // 事件通知主题
    6. QString MqttShareHandle::TopicAppEventNotify = "/Topic/EventNotify";
    7. //------------------------消息发布(推送)-------------------------
    8. // 控制设备主题
    9. QString MqttShareHandle::TopicControlDevice = "/Topic/ControlDevice";
    10. // 控制门主题(开关门)
    11. 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 的优势更加明显。

  • 相关阅读:
    请求模块(requests)
    python super用法
    【SpringBoot】搭建第一个SpringBoot项目 - group、artifact等项目元数据详解
    征途装备如何修改
    Matlab:使用plot函数绘制数据曲线
    复旦教授报告400多个安卓漏洞,历时16个月谷歌终于修复,此前曾立flag
    ISP——CSC
    1949-2020年全国31省铁路里程数据
    CAD中的超级修剪功能、使用CAD旋转命令绘制图形
    Aavegotchi 拓展 Chainlink VRF 使用场景,可用于计算 Gotchiverse 土地内的炼金币数量!
  • 原文地址:https://blog.csdn.net/qq_44667165/article/details/142062152