☰
VS2019静态编译libjsoncpp与libjson-rpc-cpp集成指南
2026/10/14 3:49:46 网站建设 项目流程

简介:这份资源是面向Windows平台C++开发者的libjsoncpp与libjson-rpc-cpp静态编译成品包,针对CSDN上其他高下载量版本缺少libjsoncpp文件、无法直接使用且仅提供x86编译的痛点,给出了X64架构下可直接链接的lib文件与完整sln工程。包内共355个文件,涵盖cpp、h源码与头文件,lib静态库、vcxproj与sln工程文件,以及obj、pdb、tlog等编译中间产物,另含json配置、py脚本与txt说明,压缩包约20.82MB。已有474人学习下载。拿到后无需自行配置依赖即可在VS2019中直接引用,也可基于工程文件二次编译为X64或x86版本,适合需要快速集成JSON解析与JSON-RPC通信能力的中高级C++开发者,省去从源码编译与依赖排查的时间成本。

1. 拿到 libjsoncpp 和 libjson-rpc-cpp 静态库,先别急着写代码

如果你在 Windows 上做 C++ 项目,需要处理 JSON 解析或者搭一套 RPC 通信,大概率绕不开 jsoncpp 和 json-rpc-cpp 这两个库。但真正让人头疼的不是写业务逻辑,而是编译。jsoncpp 本身还好,json-rpc-cpp 依赖 jsoncpp、libmicrohttpd、libcurl、argtable 等一堆东西,在 VS2019 下用 CMake 从头编一遍,顺利的话半小时,不顺利的话一天就搭进去了。这份资源就是帮你跳过这个阶段——已经用 VS2019 静态编译好的 libjsoncpp 和 libjson-rpc-cpp,拿到手直接链接就能用,不需要再折腾 CMake 和第三方依赖。适合两类人:一是刚接触 JSON-RPC 想快速跑通 demo 的新手,二是在公司项目里需要稳定静态库、不想每次换机器都重新编译的老手。下面我从库的构成、集成步骤、参数配置到踩坑排查,把整个落地过程拆开讲。

2. 静态库拆包:libjsoncpp 与 libjson-rpc-cpp 的目录结构与链接逻辑

2.1 静态编译和动态编译的区别,为什么选静态

在 Windows 下用 VS2019 编译 C++ 库,运行时库的选择直接决定了你拿到的是 .lib + .dll 还是单个 .lib。静态编译意味着把 CRT(C 运行时库)也一起打进 .lib 文件里,最终你的 exe 不需要额外带一堆 dll 就能跑。jsoncpp 和 json-rpc-cpp 如果按默认的动态方式编译,你会得到 jsoncpp.dll、json-rpc-cpp.dll 以及对应的导入库 .lib,部署时少一个 dll 就报「找不到 xxx.dll」。静态编译后,你只需要在项目里链接 .lib,编译出来的 exe 是自包含的,拷贝到别的机器上也能直接运行。

这份资源里的静态库,常见做法是使用 /MT 或 /MTd 运行时库选项编译的。你需要确认自己的项目也使用相同的运行时库设置,否则会出现 LNK2038 不匹配的链接错误。具体来说,VS2019 项目属性 → C/C++ → 代码生成 → 运行库,Release 模式选「多线程 (/MT)」,Debug 模式选「多线程调试 (/MTd)」。如果你用的是 /MD 或 /MDd,链接时就会报冲突。

2.2 目录里有什么:头文件、lib 文件、依赖顺序

一份完整的静态编译包,目录结构通常长这样:

jsoncpp-static/ ├── include/ │ └── json/ │ ├── json.h │ ├── json-forwards.h │ └── ... ├── lib/ │ ├── jsoncpp.lib (Release /MT) │ └── jsoncpp_d.lib (Debug /MTd) └── bin/ (如果有测试 exe) json-rpc-cpp-static/ ├── include/ │ └── jsonrpccpp/ │ ├── server/ │ ├── client/ │ ├── common/ │ └── ... ├── lib/ │ ├── jsonrpc.lib │ ├── jsonrpc_d.lib │ └── ... └── ...

json-rpc-cpp 本身依赖 jsoncpp,所以链接顺序很重要。在 VS2019 的链接器输入里,jsonrpc.lib 要放在 jsoncpp.lib 前面。因为链接器是从左到右解析符号的,如果 jsonrpc.lib 引用了 jsoncpp 里的符号,而 jsoncpp.lib 排在后面,链接器在第一轮扫描时找不到定义就会报 LNK2019 未解析的外部符号。另外,json-rpc-cpp 的服务端和客户端可能还依赖 Windows 自带的 winsock2.lib 和 ws2_32.lib,这两个是系统库,直接在附加依赖项里加上就行。

2.3 验证库是否可用:写一个最小 JSON 解析测试

在正式集成到项目之前,先写一个最小的测试程序验证库能不能正常链接和运行。新建一个空的控制台项目,配置好包含目录和库目录,然后写下面这段代码:

#include <json/json.h> #include <iostream> #include <string> int main() { // 构造一个 JSON 对象 Json::Value root; root["name"] = "test"; root["version"] = 1; root["tags"].append("jsoncpp"); root["tags"].append("static"); // 序列化为字符串 Json::StreamWriterBuilder writer; writer["indentation"] = " "; // 缩进两个空格 std::string output = Json::writeString(writer, root); std::cout << "Serialized:\n" << output << std::endl; // 反序列化 Json::CharReaderBuilder reader; Json::Value parsed; std::string errs; std::istringstream iss(output); bool ok = Json::parseFromStream(reader, iss, &parsed, &errs); if (!ok) { std::cerr << "Parse error: " << errs << std::endl; return 1; } std::cout << "Parsed name: " << parsed["name"].asString() << std::endl; return 0; }

这段代码做了两件事:把 Json::Value 对象序列化成带缩进的字符串,再把字符串反序列化回来。如果编译通过并且运行输出正确,说明 jsoncpp.lib 链接没问题。注意 Json::StreamWriterBuilder 的 indentation 参数控制输出格式,设为 "\t" 就是制表符缩进,设为 "" 就是紧凑输出。CharReaderBuilder 默认对格式要求比较严格,如果解析失败,errs 里会包含具体的错误位置和原因。

如果这一步就报 LNK2019,先检查附加依赖项里有没有写 jsoncpp.lib,再检查库目录路径是否包含空格或中文——VS2019 对中文路径的支持时好时坏,建议把库放在纯英文路径下。

3. 集成到 VS2019 项目:从属性配置到第一个 RPC 调用

3.1 项目属性配置:包含目录、库目录、附加依赖项

打开你的 VS2019 项目,右键项目 → 属性,需要改三个地方。第一,C/C++ → 常规 → 附加包含目录,把 jsoncpp-static/include 和 json-rpc-cpp-static/include 加进去。第二,链接器 → 常规 → 附加库目录,把两个 lib 目录加进去。第三,链接器 → 输入 → 附加依赖项,按顺序写:

jsonrpc.lib jsoncpp.lib ws2_32.lib

Debug 配置下把 jsonrpc.lib 换成 jsonrpc_d.lib,jsoncpp.lib 换成 jsoncpp_d.lib。注意 Debug 和 Release 的库不能混用,混用会导致运行时崩溃或者链接错误。另外,如果你在项目里同时用了 /MT 和 /MD,链接器会报 LNK2038:「检测到 RuntimeLibrary 的不匹配项」。解决办法是统一运行时库设置,要么全用 /MT,要么全用 /MD,取决于你拿到的静态库是用哪种方式编译的。

提示:修改完属性后,建议先清理解决方案再重新生成,避免旧的中间文件干扰链接过程。

3.2 写一个 JSON-RPC 服务端:注册方法和启动监听

json-rpc-cpp 的服务端用法比较直观,核心是继承一个抽象类,实现你要暴露的方法,然后启动 HTTP 监听。下面是一个最小服务端示例:

#include <jsonrpccpp/server.h> #include <jsonrpccpp/server/connectors/httpserver.h> #include <iostream> #include <string> class MyServer : public jsonrpc::AbstractServer<MyServer> { public: MyServer(jsonrpc::AbstractServerConnector& conn) : jsonrpc::AbstractServer<MyServer>(conn) { // 绑定方法名到成员函数 this->bindMethod("add", &MyServer::add); this->bindMethod("echo", &MyServer::echo); } // 加法方法:接收两个整数,返回和 Json::Value add(const Json::Value& request) { int a = request["params"][0].asInt(); int b = request["params"][1].asInt(); Json::Value result = a + b; return result; } // 回显方法:原样返回传入的字符串 Json::Value echo(const Json::Value& request) { std::string msg = request["params"][0].asString(); return msg; } }; int main() { // 监听 8383 端口 jsonrpc::HttpServer httpServer(8383); MyServer server(httpServer); server.StartListening(); std::cout << "Server listening on port 8383..." << std::endl; // 阻塞主线程,实际项目中可以用信号控制退出 while (true) { /* 保持运行 */ } return 0; }

bindMethod 的第一个参数是客户端调用时用的方法名,第二个参数是成员函数指针。成员函数的签名必须是 Json::Value(const Json::Value&),返回值也是 Json::Value。request 里包含 jsonrpc、method、params、id 四个字段,params 是一个数组,按顺序取参数。HttpServer 构造函数的参数是监听端口,StartListening 之后服务端就开始接受请求了。实际项目中不要用 while(true) 空转,可以用条件变量或者信号处理来优雅退出。

3.3 写一个 JSON-RPC 客户端:发起调用和处理响应

客户端代码同样简洁,核心是构造一个 Client 对象,然后调用 CallMethod:

#include <jsonrpccpp/client.h> #include <jsonrpccpp/client/connectors/httpclient.h> #include <iostream> int main() { // 连接本地 8383 端口 jsonrpc::HttpClient httpClient("http://localhost:8383"); jsonrpc::Client client(httpClient); try { // 调用 add 方法,传两个参数 Json::Value params; params.append(3); params.append(5); Json::Value result = client.CallMethod("add", params); std::cout << "3 + 5 = " << result.asInt() << std::endl; // 调用 echo 方法 Json::Value echoParams; echoParams.append("hello rpc"); Json::Value echoResult = client.CallMethod("echo", echoParams); std::cout << "Echo: " << echoResult.asString() << std::endl; } catch (jsonrpc::JsonRpcException& e) { std::cerr << "RPC error: " << e.what() << std::endl; return 1; } return 0; }

CallMethod 的第一个参数是方法名,第二个参数是 Json::Value 类型的参数数组。返回值也是 Json::Value,根据你的方法定义来取对应的类型。如果服务端返回错误,CallMethod 会抛出 JsonRpcException,catch 住之后用 what() 获取错误描述。注意 HttpClient 的 URL 要和服务端监听的地址一致,如果服务端在另一台机器上,把 localhost 换成对应的 IP。

3.4 编译运行:确认静态链接生效

把服务端和客户端分别编译成两个 exe,先运行服务端,再运行客户端。如果客户端输出「3 + 5 = 8」和「Echo: hello rpc」,说明整个链路通了。这时候你可以检查一下生成的 exe 文件大小——静态链接的 exe 通常比动态链接的大几 MB,因为 CRT 和库代码都打进去了。另外可以用 Dependency Walker 或者 VS 自带的 dumpbin /dependents 命令查看 exe 依赖了哪些 dll,如果只看到系统 dll(kernel32.dll、user32.dll 等),没有 jsoncpp.dll 和 jsonrpc.dll,就说明静态链接成功了。

注意:如果客户端报「连接被拒绝」,先确认服务端是否已经启动并且监听在正确的端口上。Windows 防火墙可能会拦截入站连接,第一次运行时留意弹窗提示。

4. 避坑排查:静态库集成中最容易翻车的五个地方

4.1 LNK2038 RuntimeLibrary 不匹配

现象:链接时报错「LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”」。

原因:你拿到的静态库是用 /MT 编译的,但你的项目用的是 /MD(或者反过来)。VS2019 默认新建控制台项目用的是 /MD,而很多第三方静态库为了部署方便会用 /MT。

解决:统一运行时库。项目属性 → C/C++ → 代码生成 → 运行库,Release 改成「多线程 (/MT)」,Debug 改成「多线程调试 (/MTd)」。改完之后清理解决方案重新生成。如果项目里引用了其他只能用 /MD 的库,那就需要找 /MD 版本的 jsoncpp 和 json-rpc-cpp,或者自己重新编译一份。

4.2 LNK2019 未解析的外部符号

现象:链接时报错「LNK2019: 无法解析的外部符号」,符号名里带有 jsonrpc 或 jsoncpp 命名空间。

原因:有三种可能。一是附加依赖项里漏写了某个 lib 文件;二是链接顺序不对,jsonrpc.lib 没有放在 jsoncpp.lib 前面;三是 Debug 配置下链接了 Release 版本的 lib。

解决:先检查附加依赖项是否完整,再调整顺序把 jsonrpc.lib 放最前面。然后确认 Debug 配置用的是 _d 后缀的 lib,Release 配置用的是不带 _d 的 lib。如果还是报错,用 dumpbin /symbols 查看 lib 里到底有没有这个符号,确认库文件没有损坏。

4.3 运行时崩溃:堆损坏或访问违例

现象:程序编译链接都通过,但运行到某个 JSON 操作时突然崩溃,报「堆损坏」或者「0xC0000005: 访问冲突」。

原因:最常见的原因是 Debug 和 Release 混用。比如你的项目是 Debug 模式,但链接了 Release 版本的 jsoncpp.lib,两个模块对堆的管理方式不同,跨模块分配和释放内存就会出问题。另一个原因是运行时库不匹配,/MT 和 /MD 混用也会导致类似症状。

解决:确保 Debug 配 Debug 库,Release 配 Release 库,运行时库设置和库的编译选项一致。如果还是崩溃,把崩溃点定位到具体的 JSON 操作,检查是否有空指针或者越界访问。jsoncpp 的 asString() 在字段不存在时会返回空字符串,但 asInt() 在字段不存在时返回 0,不会崩溃,所以崩溃通常不是 jsoncpp 本身的问题,而是内存管理不一致导致的。

4.4 服务端启动失败:端口被占用或权限不足

现象:服务端调用 StartListening 之后没有报错,但客户端连不上;或者直接抛出异常说绑定失败。

原因:端口被其他程序占用了,或者你选的端口号小于 1024 需要管理员权限。Windows 下 8383 这种高位端口一般不需要特殊权限,但如果之前有程序没退干净,端口可能还处于 TIME_WAIT 状态。

解决:换一个端口试试,比如 18383 或者 28383。用 netstat -ano | findstr 8383 查看端口占用情况,找到占用进程的 PID 后在任务管理器里结束它。如果是在公司网络环境里,确认防火墙没有拦截这个端口的入站连接。

4.5 中文乱码:JSON 字符串编码问题

现象:客户端发送包含中文的字符串,服务端收到的却是乱码,或者返回的中文在客户端显示不正常。

原因:jsoncpp 默认按 UTF-8 处理字符串,但 Windows 控制台的默认编码是 GBK。如果你在代码里直接写中文字符串字面量,VS2019 可能按 GBK 保存,传给 jsoncpp 时没有转成 UTF-8,就会出现乱码。

解决:在源文件里用 UTF-8 编码保存(文件 → 高级保存选项 → UTF-8),并且在项目属性 → C/C++ → 命令行里加上 /utf-8 选项。如果需要在控制台输出中文,用 SetConsoleOutputCP(CP_UTF8) 把控制台编码也改成 UTF-8。另一种做法是在代码里用 u8"中文" 前缀强制 UTF-8 编码。

5. 进阶技巧:用 json-rpc-cpp 做批量调用和超时控制

5.1 批量请求:一次发送多个调用

json-rpc-cpp 支持批量请求,把多个调用打包成一个数组发给服务端,服务端会返回一个数组。这在需要一次性获取多个数据的场景下很有用,能减少网络往返次数。客户端代码这样写:

// 构造批量请求 Json::Value batch(Json::arrayValue); Json::Value call1; call1["jsonrpc"] = "2.0"; call1["method"] = "add"; call1["params"].append(1); call1["params"].append(2); call1["id"] = 1; batch.append(call1); Json::Value call2; call2["jsonrpc"] = "2.0"; call2["method"] = "echo"; call2["params"].append("batch test"); call2["id"] = 2; batch.append(call2); // 发送批量请求 Json::Value batchResult = client.CallMethod("", batch); // batchResult 是一个数组,按顺序对应每个请求的结果 for (auto& item : batchResult) { std::cout << "Result id " << item["id"].asInt() << ": " << item["result"].toStyledString() << std::endl; }

批量请求的关键是 CallMethod 的第一个参数传空字符串,第二个参数传一个数组。服务端会按顺序处理每个请求,返回的数组里每个元素包含 id 和 result(或者 error)。注意批量请求不是事务性的,某个请求失败不影响其他请求的执行。

5.2 超时设置:避免客户端无限等待

默认情况下,HttpClient 的超时时间可能比较长,如果服务端挂了或者网络不通,客户端会卡住很久。可以在构造 HttpClient 的时候指定超时参数:

// 超时 5 秒 jsonrpc::HttpClient httpClient("http://localhost:8383", 5);

第二个参数是超时秒数。如果 5 秒内没有收到响应,CallMethod 会抛出异常。实际项目中根据网络状况调整这个值,局域网内可以设短一点(2-3 秒),跨机房调用可以设长一点(10-15 秒)。另外,如果服务端处理某个请求需要很长时间,客户端超时了但服务端还在继续执行,这种情况下需要考虑异步调用或者轮询结果的方式。

5.3 验证静态链接是否彻底:用 dumpbin 检查依赖

最后分享一个我每次集成静态库都会走的验证步骤。编译出 exe 之后,用 VS2019 自带的 dumpbin 工具检查依赖:

dumpbin /dependents your_app.exe

输出里如果只看到 kernel32.dll、user32.dll、ws2_32.dll 这些系统库,没有 jsoncpp.dll 和 jsonrpc.dll,就说明静态链接是彻底的。如果看到了非系统 dll,说明还有动态依赖没处理干净,部署到别的机器上可能会缺 dll。这个习惯帮我省了很多次「在我机器上能跑」的尴尬。从那以后我每次拿到新的静态库,都会先写一个最小测试程序跑通,再用 dumpbin 确认依赖,最后才集成到正式项目里。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询