尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

VS2019编译版paho.mqtt.cpp库使用全攻略:配置、示例与排坑

发布时间:2026/9/29 23:11:21

资讯中心
01
ARTICLE

VS2019编译版paho.mqtt.cpp库使用全攻略:配置、示例与排坑

VS2019编译版paho.mqtt.cpp库使用全攻略:配置、示例与排坑
简介面向需要在VS2019下使用MQTT C客户端的开发者paho.mqtt.cpp库的VS2019编译成品包源自配套博文教程可直接对照使用。paho.mqtt.cpp是Eclipse Paho官方的MQTT C客户端库支持同步/异步API常用于物联网设备接入、消息推送等场景体系结构清晰。压缩包共含550个文件包括44个h头文件、31个cpp源文件以及编译生成的dll、lib库还包含vcxproj工程文件、CMake配置、pdb调试符号、exe可执行程序等整体约64.21MB不同目录分别存放源码、构建脚本与产物便于按需检索。目前已有2976人学习下载作为配套教程的成品工程可省去手工配置第三方依赖、编译选项和链接参数的繁琐过程。下载后既能查看完整源代码和工程组织方式也能直接引用编译好的lib/dll快速集成到自己的MQTT应用中适合有一定C基础、希望加快开发进度的物联网开发者。1. 拿到现成的 paho.mqtt.cpp 库VS2019 编译版到底省了多少事做 Windows 桌面端 MQTT 接入的 C 开发者大概率都经历过这样的场景项目工期压着消息队列模块还没影翻遍 NuGet 找不到官方 paho.mqtt.cpp 的现成包GitHub 上 Release 只有源码自己配 CMake、翻 OpenSSL、调 vcpkg一搞就是两个晚上。这份 VS2019 编译完成的 paho.mqtt.cpp 库就是拿来直接解决这个痛点的——它把paho.mqtt.c和paho.mqtt.cpp两层依赖一起编好了头文件、lib、dll 按 VS2019 的目录结构整理完毕你在 Visual Studio 2019 里建好工程、把包含目录和库目录指过去、链接器加上依赖项就能开始写mqtt::client的发布订阅代码。适合谁用主力开发环境是 VS2019、不想折腾 vcpkg 和 CMake、只需要把 MQTT 客户端嵌进现有工程的 Windows C 开发者。这篇文章就把「怎么用起来」和「常见的坑」一次讲透从配置步骤到运行时报错逐个过一遍。2. 先搞清楚这份库的组成头文件、lib 与 dll 的分工2.1 库包的基本目录结构和必要文件拿到压缩包解压后典型的目录布局包含include、lib、bin或dll三层其中include下应有mqtt目录里面是 paho.mqtt.cpp 的头文件还有mqtt目录里的client.h、message.h、topic.h这些核心接口同时因为 paho.mqtt.cpp 对 C 库有依赖头文件里会#include mqtt/../mqtt/xxx.h之类相对路径引用到 paho.mqtt.c 的头文件所以include里一般还会放MQTTClient.h、MQTTProperties.h、MQTTReasonCodes.h等 C 库头文件。这两个缺一不可少了哪边编译期直接报找不到头文件。lib目录下通常区分Debug和Release两个子目录每个目录里都有paho-mqtt3a.lib异步 C 客户端、paho-mqttpp3.libC 封装库、有时还有paho-mqtt3as.lib带 SSL 的异步客户端库。bin目录对应存放运行时 DLL比如paho-mqtt3a.dll、paho-mqttpp3.dll和paho-mqtt3as.dll。这层结构决定了你在 VS2019 里要做的事把 include 目录告诉编译器把 lib 目录告诉链接器把 DLL 拷贝到 exe 输出目录。如果这份库包还带了samples或example目录建议先打开里面的 MQTT 发布订阅示例工程确认编译链接跑通后再往自己的业务代码里迁。2.2 为什么是这三个库文件paho-mqtt3a 与 paho-mqttpp3 的关系paho.mqtt.cpp 的架构是套了两层底层是 paho.mqtt.c 这个 C 库负责和 broker 的 TCP 连接、MQTT 协议报文编解码、心跳保活这些脏活上层是 paho.mqtt.cpp 的 C 封装把 C 的回调函数改造成mqtt::callback、mqtt::client这样的面向对象接口。你在代码里#include mqtt/client.h、调用mqtt::create_options时用的是 C 这套 API但链接时必须把 C 库的 lib 也加上否则符号解析不完整。// 异步客户端paho-mqtt3a.lib是底层依赖 // C 封装库paho-mqttpp3.lib依赖前者 // 如果你要用 TLS 加密连接还需要链接 paho-mqtt3as.lib #pragma comment(lib, paho-mqtt3a.lib) #pragma comment(lib, paho-mqttpp3.lib)这段#pragma comment写在stdafx.h或pch.h里是偷懒的连法VS2019 会在链接阶段自动带上这些库。但要注意链接顺序有讲究C 库必须在前、C 库在后有些场景下反了会报unresolved external symbol尤其是用了 TLS 版本时。更多时候我建议直接在项目属性的「链接器 → 输入 → 附加依赖项」里手动填填的顺序同样保持paho-mqttpp3.lib在前、paho-mqtt3a.lib在后。2.3 要不要区分 Debug 与 Release、x86 与 x64这份库如果是用 VS2019 默认配置编译的大概率包含 Win32x86和 x64 两套产物也包含 Debug 和 Release 两套。但有个关键点paho.mqtt.c 的 C 库编译时默认用的是/MD运行时库也就是动态链接到vcruntime140.dll和msvcp140.dll而你的 VS2019 工程如果设置的是/MT静态运行时链接时可能遇到LNK2038 mismatch detected for RuntimeLibrary。// 项目属性 - C/C - 代码生成 - 运行库 // Debug 对应 /MDd // Release 对应 /MD // 如果不匹配编译期报错形如 // error LNK2038: mismatch detected for RuntimeLibrary: value MTd_StaticRelease doesnt match value MDd_DynamicDebug所以拿到库后第一件事确认你的工程「配置管理器」里当前是 Debug 还是 Release、Win32 还是 x64然后去库包里对应子目录取 lib。我一般直接把四个组合全部配置好——Debug/Win32、Debug/x64、Release/Win32、Release/x64——属性表分别指到对应目录避免切配置后链接器找不到库。3. 在 VS2019 里配好工程从属性表到第一个发布订阅程序3.1 配置包含目录、库目录和附加依赖项这一节直接按可抄作业的步骤来。假设你的工程已经创建好了控制台应用或桌面应用都行打开「项目 → 属性 → VC 目录」分别设置包含目录$(SolutionDir)3rdparty\paho.mqtt.cpp\include库目录$(SolutionDir)3rdparty\paho.mqtt.cpp\lib\$(Platform)\$(Configuration)这里用$(Platform)和$(Configuration)宏是推荐做法切换 Win32/x64、Debug/Release 自动找对应目录不用手改。目录解压到哪就改成哪但建议不要把库直接放 C 盘根目录或带中文的路径下paho 的头文件包含逻辑没问题但 VS2019 的 IntelliSense 对超长路径偶尔抽风。然后点「链接器 → 输入 → 附加依赖项」加上paho-mqttpp3.lib paho-mqtt3a.lib如果你要连 TLS 端口8883把paho-mqtt3as.lib也加上同时保证paho-mqtt3a.lib不删——因为paho-mqtt3as.lib是 SSL 版异步库C 封装层的 lib 同时依赖普通版和 SSL 版。链接顺序保持上面这个次序。3.2 配置完成后跑通一个最小的发布订阅示例配好属性后先写一个最小的 MQTT 发布程序验证环境不要一上来就连业务代码。下面这段是 paho.mqtt.cpp 里最典型的同步客户端发布代码#include mqtt/client.h #include iostream #include string int main() { // 1. 指定 broker 地址、客户端标识 std::string broker tcp://127.0.0.1:1883; std::string clientId vs2019_paho_pub; // 2. 创建客户端用同步接口 mqtt::client client(broker, clientId); // 3. 连接 broker设置连接超时 5 秒 mqtt::connect_options connOpts; connOpts.set_keep_alive_interval(20); connOpts.set_clean_session(true); client.connect(connOpts); // 4. 构造消息并发布到 test/topic std::string payload hello from vs2019 paho; mqtt::message_ptr pubMsg mqtt::make_message(test/topic, payload); pubMsg-set_qos(1); client.publish(pubMsg); // 5. 断开 client.disconnect(); std::cout published OK std::endl; return 0; }这段代码里要留意的有三个参数broker地址如果连接本地调试用tcp://127.0.0.1:1883连远程则替换成tcp://ip:portmqtt::make_message的第一个参数是 topic、第二个是消息体字符串payload 也可以是二进制数据用mqtt::buffer包装std::vectoruint8_tset_qos(1)表示至少送达一次broker 收到会回 PUBACK如果设成 2 会有 PUBREC/PUBCOMP 两轮握手吞吐会下降但可靠性更高。3.3 运行前必须处理的 DLL 拷贝问题编译能过不代表运行能过。paho 这套库是动态链接的exe 启动时会去加载paho-mqttpp3.dll、paho-mqtt3a.dll如果用 TLS 还有paho-mqtt3as.dllWindows 的 DLL 搜索顺序是exe 所在目录优先于系统 PATH。你如果直接把 DLL 留在库包的bin目录里不拷贝运行时会报0xc0000135找不到 DLL。常见做法是在项目属性里加一个生成后事件命令xcopy /Y $(SolutionDir)3rdparty\paho.mqtt.cpp\bin\$(Platform)\$(Configuration)\*.dll $(OutDir)这段是拷贝当前配置对应的 DLL 到输出目录$(OutDir)默认是x64\Debug\或Debug\。如果库包的 DLL 目录没有区分$(Platform)\$(Configuration)而是全部平铺在一个bin下那直接写xcopy /Y ...bin\*.dll $(OutDir)注意拷完起一次程序确认 DLL 版本没拿错——Release 配置下不小心拷了 Debug 版 DLL运行时会莫名崩溃没有明确报错。4. 从编译到运行最常见的坑链接错、跑不动、连不上4.1 链接期报 unresolved external symbol现象编译通过链接时报LNK2019 unresolved external symbol public: void __cdecl mqtt::client::connect(...)或者一堆mqtt::string_convert相关的符号找不到。原因最常见的有三种。第一种是附加依赖项没加全只加了paho-mqttpp3.lib忘了加paho-mqtt3a.lib第二种是加了但链接顺序反了第三种是库目录指向了和当前工程位数不匹配的 lib比如 x64 工程配了 Win32 的 lib 目录链接器在 32 位库里找不到 64 位符号。解决先把附加依赖项按「pp3 → 3a → 3as」顺序填好确认「VC 目录 → 库目录」里的$(Platform)宏生效手动写死路径时务必看平台如果用了#pragma comment(lib)和属性表双写删除一种方式别两处都加。4.2 运行时崩溃在 connect报 0xC0000005现象程序启动后没几秒崩溃断点定位在client.connect()调用内部调用栈指向 paho 库内部的内存操作。原因大概率是 Debug/Release 不匹配。库包里的 Debug 版 lib/dll 是用调试运行时/MDd编的你的工程是 Release/MD两边对std::string内部布局和堆管理器的实现不同字符串在库边界传递时直接踩内存。还有一种可能是你拷的 DLL 是 Release 版但工程是 Debug 版同样崩。解决先确认「运行库」设置是/MD还是/MDd和库包的子目录对应。强烈建议 Debug 工程 Debug 库、Release 工程 Release 库不要混用。把 DLL 也按$(Configuration)分开拷贝不要一个bin里拿到底。如果实在分不清库包里哪个是 Debug 哪个是 Release用 Dependencies.exe或旧版 Dependency Walker打开 DLL 看它依赖的是VCRUNTIME140D.dll还是VCRUNTIME140.dll带 D 的就是 Debug。4.3 connect 报返回码 -1 或 ECONNREFUSED现象client.connect()抛异常或者返回-1错误信息里能看到Connection refused。原因broker 地址不对、端口没开、防火墙拦了。最常见的是本机根本没起 broker或者 broker 监听了 1883 但绑定了 127.0.0.1你用局域网 IP 去连当然拒绝还有一种情况是 broker 开启了 TLS 但你的连接串写的还是tcp://协议不匹配直接拒连。解决本地测试先确认 broker 起来了Windows 下用netstat -ano | findstr 1883看端口监听状态。连远程 broker 时 telnet 一下telnet ip 1883通的话再排查代码不通查防火墙入站规则。用 TLS 就把连接串改成ssl://ip:8883并且保证库是带 SSL 的版本链接了paho-mqtt3as.lib否则会报MQTTClient_connect: TLS not supported。4.4 消息发布成功但订阅端收不到现象publish 正常返回但另一个订阅客户端就是收不到数据broker 端日志也没看到消息转发记录。原因多半是 topic 不匹配或者 QoS 为 0 且正好赶上网络波动丢包。再有一种情况订阅端用的是mqtt::topic通配符test/#而发布端 topic 写成了test/topic/extra这没问题但如果发布端 topic 是test/topic订阅端写的是test/也能收到。真正容易忽略的是订阅端没来得及完成 SUBSCRIBE 握手就发了消息——有些示例代码把subscribe和publish写在同一个线程里subscribe是异步生效的要等回调确认后才保险。解决调 QoS 到 1 先排除丢包确认 broker 管理界面里能看到订阅关系自己在发布端也开一个订阅接收自己发的消息做回环验证。用mqtt::client的set_callback注册message_arrived回调收到消息打日志比人眼判断可靠得多。5. 进阶用法异步回调与持久会话的正确打开方式5.1 改用 consume_message 实现订阅消息处理同步接口适合快速验证但生产级的代码我一般用异步模式把mqtt::client配成异步回调注册callback子类在message_arrived里处理消息避免主线程阻塞在等待上。#include mqtt/client.h #include iostream class user_callback : public mqtt::callback { public: void message_arrived(mqtt::const_message_ptr msg) override { std::cout topic: msg-get_topic() , payload: msg-to_string() std::endl; } void connected(const std::string cause) override { std::cout connected: cause std::endl; } void connection_lost(const std::string cause) override { std::cout connection lost: cause std::endl; } }; int main() { mqtt::client client(tcp://127.0.0.1:1883, async_sub); user_callback cb; client.set_callback(cb); mqtt::connect_options opts; opts.set_keep_alive_interval(30); opts.set_clean_session(false); // 持久会话断线重连后不丢订阅 opts.set_automatic_reconnect(true); // 自动重连 client.connect(opts); client.subscribe(test/#, 1); // 主线程可以去做别的事消息由回调处理 std::this_thread::sleep_for(std::chrono::seconds(60)); return 0; }这段代码里set_clean_session(false)的语义要理解对broker 会为这个 clientId 保存订阅关系和离线消息。如果设成true每次断线重连都要重新订阅期间消息全丢。set_automatic_reconnect(true)是 paho.mqtt.cpp 在 VS2019 编译版里比较省心的特性断线后库内部按退避策略重连不用你写重连状态机。5.2 用持久会话解决断线重连的消息补偿真实项目里设备端网络抖动是常态。用持久会话时断线期间 broker 会按订阅时约定的 QoS 帮客户端缓存消息重连后自动补发这是 MQTT 协议自带的「后悔药」机制。但有几个限制消息缓存只在 broker 内存里broker 重启缓存就没了QoS 0 的消息即使持久会话也不缓存补发顺序不是严格全局有序的和 broker 实现有关。我一般会在业务侧做两层保险订阅 QoS 设 1 或 2同时本地维护一个消息序号发现序号跳变就主动向 broker 拉一次全量同步。这样即使 broker 端丢了缓存业务上也能发现对齐。用这份 VS2019 库时持久会话的配置集中在connect_options上和库的编译配置没有关系完全看代码参数。5.3 验证库与工程匹配的一站式自检清单换机器、换工程、升级 VS 版本后我每次都会强制走一遍这个验证流程先建一个空的控制台工程不做任何业务代码只包含mqtt/client.h头文件编译一次确认头文件路径正确。链接阶段加上 paho 的 lib写一个不连 broker 的mqtt::client client(tcp://127.0.0.1:1883, test)构造编译链接确认符号解析干净。起一个本地 broker如 Mosquitto for Windows跑第 2 章那段发布代码确认published OK打印出来。用 MQTT X 或 mosquitto_sub 订阅test/#确认能收到hello from vs2019 paho。核心验证一个点把工程从 Release/x64 切到 Debug/Win32重新编译跑一遍确认四个组合都过。这套流程走下来库和工程的匹配问题基本能在五分钟内暴露完。从那以后我接手任何带预编译库的 VS 工程都强制先跑一遍这五步确认库包本身没问题再往业务代码里迁省掉了很多「明明编译过了但一运行就崩」的排查时间希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。