qtmqtt: 一个开源且好用的mqtt开源客户端

目录

1.背景

2.安装

[2.1.通过 Qt Maintenance Tool 安装(推荐)](#2.1.通过 Qt Maintenance Tool 安装(推荐))

2.2.源码编译(适用于维护工具无对应版本)

3.核心类与关键接口

4.基本使用

5.实用开发技巧

6.常见问题与解决方案

7.总结


1.背景

MQTT是机器对机器(M2M)/物联网(IoT)连接协议。它被设计为一个极其轻量级的**发布/订阅** 消息传输协议。对于需要较小代码占用空间和/或网络带宽非常宝贵的远程连接非常有用,是专为受限设备和低带宽、高延迟或不可靠的网络而设计。这些原则也使该协议成为新兴的"机器到机器"(M2M)或物联网(IoT)世界的连接设备,以及带宽和电池功率非常高的移动应用的理想选择。例如,它已被用于通过卫星链路与代理通信的传感器、与医疗服务提供者的拨号连接,以及一系列家庭自动化和小型设备场景。它也是移动应用的理想选择,因为它体积小,功耗低,数据包最小,并且可以有效地将信息分配给一个或多个接收器。

MQTT的框架结构如下:

qtmqtt是qt官方提供的用于实现 MQTT 协议客户端功能的扩展模块,基于 MQTT 3.1.1 协议,支持 Qt5(5.10+)和 Qt6 版本,可用于物联网(IoT)、消息推送、设备通信等场景。

https://doc.qt.io/qt-6/zh/qtmqtt-overview.html

2.安装

Qt MQTT 是 Qt 的扩展模块,需单独安装(默认不包含在基础安装中),支持 Qt5.10 + 和 Qt6。

2.1.通过 Qt Maintenance Tool 安装(推荐)

  1. 打开 Qt 维护工具(Qt Maintenance Tool,通常在 Qt 安装目录的MaintenanceTool.exe);
  2. 选择 "添加或移除组件",输入 Qt 账号密码;
  3. 在组件列表中,展开你的 Qt 版本(如 Qt 6.5.0),找到 "Additional Libraries"→"Qt MQTT",勾选对应平台的模块(如 Windows 下的 MSVC 或 MinGW 版本);
  4. 点击 "安装",等待完成。

2.2.源码编译(适用于维护工具无对应版本)

1.获取源码

从 Qt 官方仓库克隆源码:

cpp 复制代码
https://github.com/qt/qtmqtt.git

切换到与你的 Qt 版本匹配的分支(如 Qt6.5 对应分支6.5):

cpp 复制代码
cd qtmqtt && git checkout 6.5

2.编译源码

  • 用 Qt Creator 打开源码目录中的qtmqtt.pro
  • 在项目配置中选择目标编译器(与你的 Qt 版本一致);
  • 构建项目(Build),生成库文件(.lib/.a.dll/.so)。

3.安装到 Qt 目录

  1. 编译完成后,通过make install(Linux/macOS)或nmake install(Windows)将库安装到 Qt 的默认库目录(确保 Qt 能识别)。

  2. 直接用编译出的库文件。

3.核心类与关键接口

Qt MQTT 的核心功能围绕几个关键类展开,理解这些类的作用是使用的基础:

1. QMqttClient(客户端核心类)

负责与 MQTT 服务器建立连接、管理连接状态、发布消息等,是整个模块的核心。

关键方法

  • setHostname(const QString &host):设置服务器地址(域名或 IP);
  • setPort(quint16 port):设置端口(默认 1883,SSL 通常用 8883);
  • setClientId(const QString &id):设置客户端唯一 ID(服务器通过 ID 识别客户端,建议唯一);
  • setUsername(const QString &user) / setPassword(const QString &pwd):设置认证信息(若服务器需要);
  • connectToHost() / disconnectFromHost():连接 / 断开服务器;
  • publish(const QMqttTopicName &topic, const QByteArray &message, int qos = 0, bool retain = false):发布消息(返回是否成功);
  • subscribe(const QString &topic, int qos = 0):订阅主题(返回 QMqttSubscription 指针,用于管理订阅)。

关键信号

  • stateChanged(QMqttClient::ClientState state):连接状态变化(断开 / 连接中 / 已连接);
  • errorOccurred(QMqttClient::ClientError error):发生错误时触发(如连接失败、认证失败);
  • connected():成功连接服务器后触发;
  • disconnected():断开连接后触发。

2. QMqttSubscription(订阅管理类)

QMqttClient::subscribe() 返回,用于管理订阅的主题,接收该主题的消息。

关键信号

  • messageReceived(const QByteArray &message, const QMqttTopicName &topic):收到订阅主题的消息时触发(核心信号,需绑定到自定义槽函数处理消息);
  • stateChanged(QMqttSubscription::SubscriptionState state):订阅状态变化(如订阅中 / 已订阅 / 订阅失败)。

3.QMqttTopicName(主题名类)

封装 MQTT 主题名,提供主题合法性检查(如避免非法字符),发布 / 订阅时需用此类或直接传入字符串(内部会自动转换)。

4.基本使用

使用前需在项目中配置 MQTT 模块,核心类为QMqttClient(客户端)、QMqttSubscription(订阅)。

1.项目配置(.pro 文件)

在 Qt 项目的.pro文件中添加 MQTT 模块:

cpp 复制代码
QT += mqtt

2.核心功能示例

以下是一个完整的 MQTT 客户端示例,实现 "连接服务器→订阅主题→发布消息→接收消息" 的流程。

示例代码(C++)

cpp 复制代码
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMqttClient>  // MQTT客户端类
#include <QMqttSubscription>  // 订阅类

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    // 连接/断开服务器
    void on_connectBtn_clicked();
    // 发布消息
    void on_publishBtn_clicked();
    // 处理连接状态变化
    void onStateChanged(QMqttClient::ClientState state);
    // 处理错误
    void onErrorOccurred(QMqttClient::ClientError error);
    // 处理接收到的消息
    void onMessageReceived(const QByteArray &message, const QMqttTopicName &topic);

private:
    Ui::MainWindow *ui;
    QMqttClient *mqttClient;  // MQTT客户端实例
};
#endif // MAINWINDOW_H
cpp 复制代码
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow) {
    ui->setupUi(this);

    // 初始化MQTT客户端
    mqttClient = new QMqttClient(this);
    // 设置默认服务器(可替换为公共测试服务器:test.mosquitto.org)
    ui->hostEdit->setText("test.mosquitto.org");
    ui->portSpin->setValue(1883);  // MQTT默认端口
    ui->topicEdit->setText("qt/mqtt/test");  // 测试主题

    // 绑定信号槽(状态变化、错误、消息接收)
    connect(mqttClient, &QMqttClient::stateChanged, this, &MainWindow::onStateChanged);
    connect(mqttClient, &QMqttClient::errorOccurred, this, &MainWindow::onErrorOccurred);
}

MainWindow::~MainWindow() {
    delete ui;
}

// 连接/断开服务器
void MainWindow::on_connectBtn_clicked() {
    if (mqttClient->state() == QMqttClient::Connected) {
        // 已连接:断开连接
        mqttClient->disconnectFromHost();
        ui->connectBtn->setText("连接");
    } else {
        // 未连接:设置服务器参数并连接
        mqttClient->setHostname(ui->hostEdit->text());  // 服务器地址
        mqttClient->setPort(ui->portSpin->value());     // 端口
        // 可选:设置客户端ID(建议唯一,默认自动生成)
        mqttClient->setClientId("QtMqttClient_" + QString::number(qrand()));
        // 可选:设置用户名/密码(若服务器需要)
        // mqttClient->setUsername("user");
        // mqttClient->setPassword("pass");
        // 连接服务器
        mqttClient->connectToHost();
    }
}

// 发布消息
void MainWindow::on_publishBtn_clicked() {
    if (mqttClient->state() != QMqttClient::Connected) {
        QMessageBox::warning(this, "错误", "未连接到服务器!");
        return;
    }
    // 发布消息:主题、内容、QoS(0/1/2)、是否保留
    QMqttTopicName topic(ui->topicEdit->text());
    QByteArray message = ui->messageEdit->text().toUtf8();
    mqttClient->publish(topic, message, 1, false);  // QoS=1(确保消息至少到达一次)
    ui->logEdit->append("发布消息:" + message);
}

// 处理连接状态变化
void MainWindow::onStateChanged(QMqttClient::ClientState state) {
    switch (state) {
        case QMqttClient::Disconnected:
            ui->logEdit->append("已断开连接");
            break;
        case QMqttClient::Connecting:
            ui->logEdit->append("正在连接...");
            break;
        case QMqttClient::Connected:
            ui->logEdit->append("已连接到服务器");
            ui->connectBtn->setText("断开");
            // 连接成功后订阅主题
            auto subscription = mqttClient->subscribe(ui->topicEdit->text(), 1);  // QoS=1
            if (subscription) {
                connect(subscription, &QMqttSubscription::messageReceived,
                        this, &MainWindow::onMessageReceived);
                ui->logEdit->append("已订阅主题:" + ui->topicEdit->text());
            }
            break;
    }
}

// 处理错误
void MainWindow::onErrorOccurred(QMqttClient::ClientError error) {
    ui->logEdit->append("错误:" + mqttClient->errorString());
}

// 处理接收到的消息
void MainWindow::onMessageReceived(const QByteArray &message, const QMqttTopicName &topic) {
    ui->logEdit->append(QString("收到消息(主题:%1):%2")
                        .arg(topic.name()).arg(QString(message)));
}

5.实用开发技巧

在实际开发中,除了基础功能,还需处理断线重连、消息可靠性、加密等问题,以下是常用技巧:

1.断线自动重连

MQTT 客户端可能因网络波动断开连接,需实现自动重连机制:

cpp 复制代码
// 在断开连接时启动重连定时器
connect(mqttClient, &QMqttClient::disconnected, this, [=]() {
    ui->logEdit->append("连接断开,将在5秒后重试...");
    QTimer::singleShot(5000, this, [=]() {
        if (mqttClient->state() == QMqttClient::Disconnected) {
            mqttClient->connectToHost(); // 重试连接
        }
    });
});

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

当客户端异常断开(如崩溃、网络中断),服务器会自动向指定主题发布 "遗嘱消息",用于通知其他客户端:

cpp 复制代码
// 配置遗嘱消息(必须在连接前设置)
mqttClient->setWillTopic("qt/mqtt/will"); // 遗嘱主题
mqttClient->setWillMessage("客户端意外离线"); // 遗嘱内容
mqttClient->setWillQoS(1); // 遗嘱消息的QoS等级
mqttClient->setWillRetain(false); // 是否保留遗嘱消息

3.SSL 加密连接(支持 TLS)

对于需要加密的场景(如生产环境),需配置 SSL 证书:

cpp 复制代码
// 初始化SSL配置
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
// 加载CA证书(若服务器使用自签名证书,需指定CA)
QList<QSslCertificate> caCerts = QSslCertificate::fromPath("ca.crt"); // 替换为实际证书路径
if (!caCerts.isEmpty()) {
    sslConfig.setCaCertificates(caCerts);
}
// 禁用证书验证(仅测试用,生产环境不建议)
// sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);

// 应用SSL配置并连接
mqttClient->setSslConfiguration(sslConfig);
mqttClient->setPort(8883); // SSL默认端口
mqttClient->connectToHost();

4.主题通配符使用

订阅时支持通配符匹配多个主题,简化订阅逻辑:

  • +:匹配单个层级(如 sensors/+/temp 匹配 sensors/room1/tempsensors/room2/temp);
  • #:匹配所有子层级(如 sensors/# 匹配 sensors/room1/tempsensors/room2/humidity,必须放在末尾)。

示例:

cpp 复制代码
// 订阅所有传感器相关主题
mqttClient->subscribe("sensors/#", 1);

6.常见问题与解决方案

1.连接失败:"Connection refused: Not authorized"

  • 原因:服务器需要认证,但未设置用户名 / 密码,或认证信息错误。
  • 解决:用 setUsername()setPassword() 配置正确的认证信息。

2.发布消息后未收到

  • 检查主题是否完全匹配(MQTT 主题区分大小写,如 testTest 是不同主题);
  • 确认客户端已成功订阅主题(通过 QMqttSubscription::stateChanged 检查订阅状态);
  • 检查 QoS 等级:若服务器或中间节点不支持高 QoS(如 QoS 2),可能导致消息丢失。

3.Qt5 与 Qt6 兼容性差异

  • Qt6 中 QMqttClient::ClientError 枚举值名称略有调整(如 InvalidProtocolVersion 改为 ProtocolVersionError);
  • Qt6 移除了部分过时接口(如 QMqttClient::willTopic() 改为 willTopic() 的常量版本),迁移时需注意接口变化。

7.总结

Qt MQTT 适用于需要低带宽、高可靠性的消息通信场景,例如:

  • 物联网设备间通信(如传感器数据上报、设备控制指令);
  • 跨平台消息推送(桌面 / 移动设备接收服务器通知);
  • 分布式系统中的轻量级消息传递。

Qt MQTT 的优势在 基于 Qt 框架的开发场景 中尤为突出,尤其是:

  • 跨平台 GUI 应用(如物联网监控平台、设备管理工具);
  • 嵌入式设备(如传感器节点、工业控制器);
  • 需要与 Qt 其他模块(如网络、界面、硬件交互)深度协同的项目。

如果应用不基于 Qt 框架(如纯 Python 脚本、Java 后端),第三方客户端(如 paho-mqtt、Eclipse Paho Java)可能更合适;但如果是 Qt 开发,Qt MQTT 是性价比最高的选择。

参考:

http://mqtt.p2hp.com/

相关推荐
向上的车轮3 小时前
开源Outline系统基础知识要点及避坑要点
开源·开源文库
小苏兮3 小时前
【数据结构】二叉搜索树
开发语言·数据结构·c++·学习·1024程序员节
腾昵猫3 小时前
程序员的自我修养(三)
c++
晨曦(zxr_0102)3 小时前
CSP-X 2024 复赛编程题全解(B4104+B4105+B4106+B4107)
数据结构·c++·算法
·白小白3 小时前
力扣(LeetCode) ——15.三数之和(C++)
c++·算法·leetcode
无限进步_4 小时前
深入理解C语言scanf函数:从基础到高级用法完全指南
c语言·开发语言·c++·后端·算法·visual studio
Wild_Pointer.4 小时前
Qt Creator:避免QRunnable和QObject多重继承
开发语言·qt
m0_748240254 小时前
C++仿Muduo库Server服务器模块实现 基于Reactor模式的高性
服务器·c++·php
南棱笑笑生5 小时前
20251027在Ubuntu20.04.6上编译AIO-3576Q38开发板的Buildroot系统解决qt5webengine编译异常的问题
开发语言·qt·rockchip