异步发布qos>0消息必须设置delivery_complete_callback,否则无法确认broker是否收到;connect后需在connected_callback中发消息,不可仅wait();clean_session需设false并固定client id才能接收离线消息;topic须用std::string构造防\0截断。

异步发布必须配 delivery_complete_callback,否则QoS>0消息等于“发了但不知死活”
用 mqtt::async_client 调 publish() 时,如果只传主题和 payload,QoS 设为 1 或 2,消息大概率进了网络栈就消失——broker 是否收到、是否确认,你完全不知道。这不是 bug,是设计使然:异步发布不等 broker 回应,只等“提交成功”,而 delivery 确认得靠回调。
- 必须调
client.set_delivery_complete_callback(),否则delivery_complete()永远不会触发 - QoS=0 的消息压根不走 delivery 流程,所以这个回调对它无效;别指望靠它判断 QoS=0 是否送达
- 回调里拿到的
mqtt::delivery_token_ptr可以调get_message_id()或is_complete()做日志或重试标记 - 如果你在回调里做耗时操作(比如写磁盘、发 HTTP),会阻塞 Paho 内部线程池——建议只记状态,另起线程处理
connect() 后立刻 publish()?错,得等 connected_callback 触发后再发
很多人写 client.connect()->wait() 就以为连上了,马上调 publish(),结果抛 std::runtime_error,错误信息含 "not connected"。因为 connect()->wait() 只等连接动作发起完成,不代表 TCP 握手+MQTT CONNECT 报文交换+CONNACK 返回这一整套流程已结束。
- 正确姿势:先注册
client.set_connected_callback(),再调client.connect(),在回调里发消息 -
connect_options中set_clean_session(true)是默认值,但若需接收离线消息,必须设为false并确保 client ID 固定 - 如果 broker 需要认证,
connOpts.set_user_name()和connOpts.set_password()必须在connect()前设置,晚了无效 - 心跳间隔
set_keep_alive_interval(20)别设太小,嵌入式设备网络抖动时容易被 broker 主动断连
主题名写成 "sensor/temp\0"?C 字符串截断会导致订阅/发布全失效
MQTT 协议要求 topic 是 UTF-8 编码的字符串,长度由协议头字段明确定义。C++ 里若用 C 风格字面量加 <p>MQTT 协议要求 topic 是 UTF-8 编码的字符串,长度由协议头字段明确定义。C++ 里若用 C 风格字面量加 <code>\0,std::string("sensor/temp\0") 构造时会在第一个 \0 截断,实际传给 broker 的 topic 变成 "sensor/temp" —— 表面看没报错,但 broker 收到的是短 topic,订阅者根本收不到。
std::string("sensor/temp<p>MQTT 协议要求 topic 是 UTF-8 编码的字符串,长度由协议头字段明确定义。C++ 里若用 C 风格字面量加 <code>\0,std::string("sensor/temp\0") 构造时会在第一个 \0 截断,实际传给 broker 的 topic 变成 "sensor/temp" —— 表面看没报错,但 broker 收到的是短 topic,订阅者根本收不到。") 构造时会在第一个 <p>MQTT 协议要求 topic 是 UTF-8 编码的字符串,长度由协议头字段明确定义。C++ 里若用 C 风格字面量加 <code>\0,std::string("sensor/temp\0") 构造时会在第一个 \0 截断,实际传给 broker 的 topic 变成 "sensor/temp" —— 表面看没报错,但 broker 收到的是短 topic,订阅者根本收不到。 截断,实际传给 broker 的 topic 变成 "sensor/temp" —— 表面看没报错,但 broker 收到的是短 topic,订阅者根本收不到。- 永远用
std::string构造 topic,比如"sensor/temp"或std::string(topic_str) - 避免从 C 接口(如
char*)直接构造,除非你确认源字符串无内嵌\0 - 调试时可用
std::cout 打印长度,一眼识破截断 - topic 层级别太多(如
a/b/c/d/e/f/g)不影响协议,但部分 broker 有长度限制(常见上限 65535 字节),超长会被静默拒绝
用 QMqttClient 还是 Paho?看你是 Qt 应用还是纯 C++ 服务
Qt 自带的 QMqttClient 和 Eclipse Paho C++ 是两套东西,不能混用。前者绑死 Qt 事件循环,后者依赖独立线程池,选错会导致主线程卡死或信号不触发。
立即学习“C++免费学习笔记(深入)”;
- Qt GUI 或 QML 项目:用
QMqttClient,它天然适配QObject生命周期和信号槽,connected、messageReceived信号开箱即用 - 后台服务、嵌入式 daemon、或需要精细控制线程模型的场景:用 Paho
mqtt::async_client,它不依赖 Qt,可自由管理连接/重连逻辑 - 别试图把 Paho 的 callback 绑进 Qt 信号——Paho 回调运行在内部线程,直接 emit 信号可能崩溃;必须用
QMetaObject::invokeMethod(..., Qt::QueuedConnection)转发 - 两者都支持 TLS,但 Paho 需手动 link
libssl,QMqttClient在 Qt 6.5+ 默认启用 OpenSSL,配置更轻量










