目录
- 一、前言
- 二、开源库简介
- 三、主函数结构
- [四、注册 RPC 方法](#四、注册 RPC 方法)
- [五、Print 函数实现](#五、Print 函数实现)
- [六、add 函数实现](#六、add 函数实现)
- 七、串口工具测试
- 八、总结
- 九、结尾
一、前言
大家好,这里是 Hello_Embed。上篇完成了 JSON 与 JsonRPC 的概念入门------了解了 JSON 的 7 种数据类型、cJSON 的增删改查,以及 JsonRPC "本地函数语法 + JSON 网络传输" 的工作原理。
本篇进入实战,基于开源库 jsonrpc-cpp 搭建 JsonRPC TCP Server,在本机上运行起来,并用串口调试工具手动发送 JSON 报文进行测试。
二、开源库简介
本文使用的开源项目:https://github.com/s-vincent/jsonrpc-cpp
该库基于 Jsoncpp + socket 封装,提供了开箱即用的 Json::Rpc::TcpServer 类,支持方法注册、监听、消息分发等完整流程,非常适合在上位机中快速搭建 JsonRPC 服务端。
注意 :编译需要先链接 Jsoncpp 和 jsonrpc-cpp 库。如果使用 VS Code,推荐在
tasks.json中添加 Jsoncpp 的链接选项和各源文件路径,生成可执行程序后运行.\tcp-server.exe。本文略过编译步骤,聚焦代码结构。
三、主函数结构
示例工程的 tcp_server.cpp 主函数如下:
cpp
int main(int argc, char** argv)
{
TestRpc a; // RPC 方法的宿主对象
Json::Rpc::TcpServer server(std::string("127.0.0.1"), 8086); // 监听本地 8086 端口
(void)argc; // 消除编译器未使用参数的警告
(void)argv;
/* 初始化网络层(Windows 下需要 WSAStartup) */
if (!networking::init())
{
std::cerr << "Networking initialization failed" << std::endl;
exit(EXIT_FAILURE);
}
/* 注册信号处理,Ctrl+C / kill 信号时优雅退出 */
if (signal(SIGTERM, signal_handler) == SIG_ERR)
std::cout << "Error signal SIGTERM will not be handled" << std::endl;
if (signal(SIGINT, signal_handler) == SIG_ERR)
std::cout << "Error signal SIGINT will not be handled" << std::endl;
/* 向服务器注册 RPC 方法,字符串是客户端调用时使用的方法名 */
server.AddMethod(new Json::Rpc::RpcMethod<TestRpc>(a, &TestRpc::Print, std::string("print")));
server.AddMethod(new Json::Rpc::RpcMethod<TestRpc>(a, &TestRpc::add, std::string("add")));
server.AddMethod(new Json::Rpc::RpcMethod<TestRpc>(a, &TestRpc::Notify, std::string("notify")));
/* server.SetEncapsulatedFormat(Json::Rpc::NETSTRING); */ // 可选:启用 Netstring 封装格式
/* 绑定地址 + 端口 */
if (!server.Bind())
{
std::cout << "Bind failed" << std::endl;
exit(EXIT_FAILURE);
}
/* 开始监听连接 */
if (!server.Listen())
{
std::cout << "Listen failed" << std::endl;
exit(EXIT_FAILURE);
}
g_run = 1;
std::cout << "Start JSON-RPC TCP server" << std::endl;
/* 主循环:每次最多等待 1000ms,有消息则分发给对应 RPC 方法处理 */
while (g_run)
{
server.WaitMessage(1000);
}
std::cout << "Stop JSON-RPC TCP server" << std::endl;
server.Close(); // 关闭服务器套接字
networking::cleanup(); // 清理网络层资源(Windows 下 WSACleanup)
return EXIT_SUCCESS;
}
解析 :
WaitMessage(1000)是整个服务器的核心驱动------它在内部调用select()等待最多 1000ms,有新连接或新数据时立即分发到已注册的 RPC 方法。超时后继续循环,同时检查g_run标志,这样信号处理函数只需把g_run置 0,主循环就会自然退出。
四、注册 RPC 方法
注册的核心语句:
cpp
server.AddMethod(new Json::Rpc::RpcMethod<TestRpc>(
a, // 方法所属的对象实例
&TestRpc::Print, // 指向成员函数的指针
std::string("print") // 客户端调用时使用的方法名字符串
));
这行代码的含义:客户端发来 "method": "print" 时,服务器会调用对象 a 的 TestRpc::Print 函数。方法名是字符串映射,可以随意起名,客户端和服务端约定好即可。
五、Print 函数实现
Print 是最简单的 RPC 方法------收到请求后打印内容,并返回 "success":
cpp
bool TestRpc::Print(const Json::Value& root, Json::Value& response)
{
/* root 是客户端发来的完整 JSON 请求,包含 jsonrpc/method/params/id 字段 */
std::cout << "Receive query: " << root << std::endl;
/* 构造 JSON-RPC 2.0 规范的响应 */
response["jsonrpc"] = "2.0"; // 协议版本,固定填 "2.0"
response["id"] = root["id"]; // 回显请求的 id,便于客户端匹配
response["result"] = "success"; // 返回值
return true; // 返回 true 表示处理成功,库会自动把 response 序列化并发回
}
解析 :所有 RPC 方法的签名都是固定的
(const Json::Value& root, Json::Value& response)------root是收到的请求,response是要填写的返回值。库负责收发、序列化/反序列化,我们只需要专注业务逻辑,非常干净。
六、add 函数实现
add 是一个带参数的 RPC 方法:从 params 数组里取两个整数相加,把结果写进 response:
cpp
bool TestRpc::add(const Json::Value& root, Json::Value& response)
{
/* 客户端调用格式:{"jsonrpc":"2.0","method":"add","params":[1,2],"id":1} */
Json::Value params = root["params"]; // 取出 params 数组
int a = params[0u].asInt(); // 取第 1 个参数,0u 表示下标 0(无符号整数避免歧义)
int b = params[1u].asInt(); // 取第 2 个参数
int sum = a + b;
/* 构造响应 */
response["jsonrpc"] = "2.0";
response["id"] = root["id"];
response["result"] = sum; // 把计算结果直接放入 result 字段
return true;
}
解析 :
params[0u]中0u是无符号整数字面量。Jsoncpp 的[]运算符同时重载了int和UInt版本,用0u可以明确调用数组下标版本,避免与按字符串键名查找产生歧义,是一个常见的写法习惯。
七、串口工具测试
编译成功后,运行 .\tcp-server.exe,打开串口调试工具,模式切换为 TCP Client ,目标 IP 127.0.0.1,端口 8086。
测试 Print 方法
发送:
json
{"jsonrpc":"2.0","method":"print","id":1}
终端输出:
Receive query:
{
"id" : 1,
"jsonrpc" : "2.0",
"method" : "print"
}
服务端收到请求后打印完整报文,如下图所示:

测试 add 方法
发送:
[10:03:33.402] 发→ {"jsonrpc":"2.0","method":"add","params":[2,2],"id":1}
[10:03:33.403] 收← {"id":1,"jsonrpc":"2.0","result":4}
2 + 2 = 4,结果正确,测试通过。
八、总结
| 知识点 | 要点 |
|---|---|
| jsonrpc-cpp 库 | 基于 Jsoncpp + socket 封装,TcpServer 类开箱即用 |
AddMethod |
将 C++ 成员函数绑定到 RPC 方法名字符串,客户端按名调用 |
| RPC 函数签名 | (const Json::Value& root, Json::Value& response),固定格式 |
| 读取参数 | root["params"][0u].asInt(),0u 避免 [] 重载歧义 |
| 构造响应 | 填写 jsonrpc、id、result 三个字段,返回 true |
| 主循环 | WaitMessage(1000) 驱动消息分发,信号置 g_run=0 退出 |
九、结尾
本篇搭建了 JsonRPC TCP Server,完成了 Print 和 add 两个 RPC 方法的注册与实现,并通过串口调试工具验证了请求-响应的完整流程。
下一篇将实现对应的 JsonRPC TCP Client,让两端真正联通起来,敬请期待~
Hello_Embed 继续带你从原理到实践,掌握嵌入式上位机开发的核心技能,敬请关注~