1、简述
RPC:Remote Procedure Call,远程程序调用,像调用本地函数一样调用远程服务器上的方法,和HTTP请求类似,但是每个功能分的较细,同时也规定了参数格式。
常见的RPC如下:
| 特性 | XML-RPC | SOAP | REST | JSON-RPC | gRPC |
|---|---|---|---|---|---|
| 基础协议 | HTTP + XML | HTTP + XML | HTTP | HTTP + JSON | HTTP/2 + Protobuf |
| 复杂度 | 低 | 高 | 中 | 低 | 中高 |
| 消息体积 | 大 | 更大 | 中 | 小 | 极小 |
| 性能 | 一般 | 较差 | 良好 | 良好 | 优秀 |
| 数据类型 | 有限 | 丰富 | 灵活 | 简单 | 强大 |
| 安全性 | 依赖 HTTP | 内置 WS-Security | 需额外实现 | 依赖 HTTP | 内置 TLS |
| 适用场景 | 简单跨平台 | RPC 企业级复杂服务 | Web API | 轻量级 RPC | 高性能微服务 |
2、XML-RPC
XML-RPC 是一种基于 XML 编码和HTTP 传输的远程过程调用协议。
本质是一种分布式计算协议,它将远程函数调用封装为 HTTP POST 请求,使用 XML 格式描述调用的方法名和参数,服务器执行后将结果以 XML 格式返回给客户端。
2.1 工作原理
XML-RPC 的通信流程遵循典型的请求 - 响应模式,步骤如下
- 客户端请求:构造 XML 格式的 RPC 请求,包含方法名和参数,通过 HTTP POST 发送到服务器特定端点
- 服务器接收: 解析 HTTP 请求头,提取 XML payload
- XML 解析:解析 XML 文档,识别目标方法和参数值
- 方法执行: 在服务器端调用对应的方法,传入解析后的参数
- 结果封装: 将执行结果(成功返回值或错误信息)编码为 XML 格式
- 响应返回: 通过 HTTP 响应将 XML 结果返回给客户端
- 客户端处理: 解析响应 XML,提取结果并进行后续处理
2.2 HTTP 传输层要求
必须使用HTTP POST方法,不支持 GET
请求头必须包含:
- Content-Type: text/xml
- Content-Length: 正确的请求体长度
- User-Agent 和 Host 字段
- 标准端点路径:通常为 /RPC2,但可自定义
2.3 XML 消息结构
1)请求消息(methodCall)
xml
<?xml version="1.0"?>
<methodCall>
<methodName>calculator.add</methodName> <!-- 必选:方法名,支持命名空间 -->
<params> <!-- 可选:参数列表 -->
<param><value><i4>5</i4></value></param> <!-- 参数1:整数5 -->
<param><value><double>3.2</double></value></param> <!-- 参数2:浮点数3.2 -->
</params>
</methodCall>
2)成功响应:
xml
<?xml version="1.0"?>
<methodResponse>
<params>
<param><value><double>8.2</double></value></param> <!-- 返回结果:8.2 -->
</params>
</methodResponse>
3)错误响应:
xml
<?xml version="1.0"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><i4>4</i4></value> <!-- 错误代码 -->
</member>
<member>
<name>faultString</name>
<value><string>Invalid parameters</string></value> <!-- 错误描述 -->
</member>
</struct>
</value>
</fault>
</methodResponse>
2.4 数据类型
XML-RPC 定义了11 种标准数据类型
- 整数
<i4> 或 <int>32 位有符号整数 - 布尔值
<boolean>0(假)或 1(真) - 字符串
<string>文本字符串(可省略标签) - 双精度浮点数
<double>64 位浮点数 - 日期时间
<dateTime.iso8601>ISO 8601 格式日期时间 - 二进制数据
<base64>Base64 编码的二进制数据 - 数组
<array>有序值列表,包含在<data>标签中 - 结构体
<struct>键值对集合,包含多个<member> - 64 位整数
<i8>非标准扩展,不同实现可能有差异 - 空值
<nil>非标准扩展,用于表示空值 - 长字符串
<string>无长度限制,通过 XML 自然支持
1)数组示例
xml
<value>
<array>
<data>
<value><string>apple</string></value>
<value><string>banana</string></value>
<value><i4>10</i4></value>
</data>
</array>
</value>
2)结构体示例
xml
<value>
<struct>
<member>
<name>name</name>
<value><string>John Doe</string></value>
</member>
<member>
<name>age</name>
<value><i4>30</i4></value>
</member>
</struct>
</value>
2.5 C++库 libxmlrpc
源码下载:
https://xmlrpc-c.sourceforge.io/
命令安装:
C库
sudo apt install libxmlrpc-core-c3 libxmlrpc-core-c3-dev
C++封装
sudo apt install libxmlrpc-c++8v5 libxmlrpc-c++8-dev
命令行工具
sudo apt install xmlrpc-api-utils
示例下载:
https://sourceforge.net/p/xmlrpc-c/code/HEAD/tree/trunk/
3、JSON-RPC
JSON-RPC 和 XML-RPC 比较相似,都是通过HTTP传输,消息体一个为JSON,另一个为XML
3.1 和XML-RPC相比
1)优缺点总结
XML-RPC
- 优点:早年跨平台通用、规范统一、老旧系统全覆盖
- 缺点:笨重、慢、冗余高、开发繁琐、现代项目基本淘汰
JSON-RPC
- 优点:轻量、高速、易调试、前端友好、生态成熟、适配微服务
- 缺点:无原生日期 / 二进制专用类型,老古董系统不兼容
3.2 C++库:jsonrpccpp
3.2.1 安装
sudo apt install libjsonrpccpp-dev libjsonrpccpp-tools
3.2.2 使用
1)服务端:server.cpp
cpp
#include <iostream>
#include <jsonrpccpp/server.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
using namespace jsonrpc;
using namespace std;
class MyServer : public AbstractServer<MyServer>
{
public:
MyServer(AbstractServerConnector &connector) : AbstractServer<MyServer>(connector)
{
bindAndAddMethod(Procedure("add", PARAMS_BY_POSITION, JSON_INTEGER, "a", JSON_INTEGER, "b", JSON_INTEGER, NULL), &MyServer::add);
bindAndAddMethod(Procedure("sayHello", PARAMS_BY_POSITION, JSON_STRING, "name", JSON_STRING, NULL), &MyServer::sayHello);
}
void add(const Json::Value& params, Json::Value& result)
{result = params[0].asInt() + params[1].asInt();}
void sayHello(const Json::Value& params, Json::Value& result)
{result = "Hello, " + params[0].asString() + "!";}
};
int main()
{
HttpServer server(8080);
MyServer serv(server);
cout << "服务端运行在 8080 端口" << endl;
serv.StartListening();
getchar();
serv.StopListening();
return 0;
}
2)客户端:client.cpp
cpp
#include <iostream>
#include <jsonrpccpp/client.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
using namespace jsonrpc;
using namespace std;
int main()
{
try{
HttpClient httpClient("http://localhost:8080");
Client rpc(httpClient, JSONRPC_CLIENT_V2);
Json::Value params_add;
params_add.append(10); // 构造 JSON 数组 [10, 20]
params_add.append(20);
Json::Value sum = rpc.CallMethod("add", params_add);
Json::Value params_hello;
params_hello.append("Ubuntu 22.04"); // 构造 JSON 数组 ["Ubuntu 22.04"]
Json::Value greet = rpc.CallMethod("sayHello", params_hello);
cout << "add(10, 20) = " << sum.asInt() << endl;
cout << greet.asString() << endl;
}catch (JsonRpcException& e){
cerr << "错误: " << e.what() << endl;
}
return 0;
}
3.2.3 编译、测试
g++ -std=c++11 server.cpp -o server -ljsonrpccpp-server -ljsonrpccpp-common -ljsoncpp
g++ -std=c++11 client.cpp -o client -ljsonrpccpp-client -ljsonrpccpp-common -ljsoncpp
3.3.4 卸载
sudo apt remove libjsonrpccpp-dev libjsonrpccpp-client0 libjsonrpccpp-common0 \
libjsonrpccpp-server0 libjsonrpccpp-tools
3.4 C++库:json-rpc-cxx
Jsonrpccpp 版本比较旧,有各种问题,建议使用 json-rpc-cxx
下载地址:
https://github.com/jsonrpcx/json-rpc-cxx
安装依赖:
sudo apt install nlohmann-json3-dev
json-rpc-cxx 依赖第三方库:
cpp-httplib doctest nlohmann