qtmqtt: 一个开源且好用的mqtt开源客户端
目录
1.背景
2.安装
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 安装(推荐)
- 打开 Qt 维护工具(Qt Maintenance Tool,通常在 Qt 安装目录的
MaintenanceTool.exe); - 选择 “添加或移除组件”,输入 Qt 账号密码;
- 在组件列表中,展开你的 Qt 版本(如 Qt 6.5.0),找到 “Additional Libraries”→“Qt MQTT”,勾选对应平台的模块(如 Windows 下的 MSVC 或 MinGW 版本);
- 点击 “安装”,等待完成。
2.2.源码编译(适用于维护工具无对应版本)
1.获取源码
从 Qt 官方仓库克隆源码:
https://github.com/qt/qtmqtt.git
切换到与你的 Qt 版本匹配的分支(如 Qt6.5 对应分支6.5):
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 模块:
QT += mqtt
2.核心功能示例
以下是一个完整的 MQTT 客户端示例,实现 “连接服务器→订阅主题→发布消息→接收消息” 的流程。
示例代码(C++)
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QMqttClient> // MQTT客户端类
#include <QMqttSubscription> // 订阅类QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic: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
// 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=1if (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 客户端可能因网络波动断开连接,需实现自动重连机制:
// 在断开连接时启动重连定时器
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)
当客户端异常断开(如崩溃、网络中断),服务器会自动向指定主题发布 “遗嘱消息”,用于通知其他客户端:
// 配置遗嘱消息(必须在连接前设置)
mqttClient->setWillTopic("qt/mqtt/will"); // 遗嘱主题
mqttClient->setWillMessage("客户端意外离线"); // 遗嘱内容
mqttClient->setWillQoS(1); // 遗嘱消息的QoS等级
mqttClient->setWillRetain(false); // 是否保留遗嘱消息
3.SSL 加密连接(支持 TLS)
对于需要加密的场景(如生产环境),需配置 SSL 证书:
// 初始化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/temp、sensors/room2/temp);#:匹配所有子层级(如sensors/#匹配sensors/room1/temp、sensors/room2/humidity,必须放在末尾)。
示例:
// 订阅所有传感器相关主题
mqttClient->subscribe("sensors/#", 1);
6.常见问题与解决方案
1.连接失败:“Connection refused: Not authorized”
- 原因:服务器需要认证,但未设置用户名 / 密码,或认证信息错误。
- 解决:用
setUsername()和setPassword()配置正确的认证信息。
2.发布消息后未收到
- 检查主题是否完全匹配(MQTT 主题区分大小写,如
test和Test是不同主题); - 确认客户端已成功订阅主题(通过
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/
