rpc 的使用

RPC 介绍

核心思想:

让调用远程服务像调用本地函数一样简单

1
2
3
4
// 本地函数调用
int result = local_add(1, 2);
// RPC 调用 - 看起来一样,但实际在远程执行
int result = remote_add(1, 2); // 这个函数在另一台机器上执行

解决了分布式系统中的服务间通信,同时隐藏了网络通信的复杂性,提供了类型安全的远程调用

RPC 基本组件

一个完整的 RPC 系统通常包含以下三个层次:

  1. 接口定义语言(IDL, Interface Definition Language)
    —— 描述服务方法和数据结构。
  2. 数据序列化格式
    —— 将结构化数据转换为可传输的字节流。
  3. 网络通信协议
    —— 负责请求/响应的传输、连接管理、错误处理等。

protobuf 能解决前两个问题,比如

1
2
3
4
5
6
// 定义接口
service UserService { // 服务接口定义
rpc GetUser(GetUserReq) returns (UserRsp); // 远程方法定义
rpc CreateUser(CreateUserReq) returns (UserRsp);
}
message GetUserReq { int32 user_id = 1; }
1
2
3
4
5
6
7
8
// Protobuf 提供序列化方法
GetUserReq request;
request.set_user_id(123);
std::string serialized_data = request.SerializeAsString();

// 反序列化
GetUserReq new_request;
new_request.ParseFromString(serialized_data);

rpc 框架通常能自己解决第三层网络协议

  • RPC 系统分层

第一层:接口描述文件层(IDL Layer),通常用 .proto 来定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// user_service.proto - 接口描述层
syntax = "proto3";

service UserService {
rpc GetUser(GetUserRequest) returns (UserResponse);
rpc CreateUser(CreateUserRequest) returns (UserResponse);
}

message GetUserRequest {
int32 user_id = 1;
}

message UserResponse {
int32 user_id = 1;
string name = 2;
string email = 3;
}

第二层:RPC 协议层(Protocol Layer),通常由 protoc.exe配合 RPC 的插件使用,生成的是比如 .grpc.pb.cc.grpc.pb.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 由 protoc 生成的代码 - RPC 协议层
class UserService_Stub : public ::google::protobuf::Service {
public:
// 客户端存根 - 封装调用细节
void GetUser(::google::protobuf::RpcController* controller,
const GetUserRequest* request,
UserResponse* response,
::google::protobuf::Closure* done);

// 服务端骨架 - 提供实现基类
virtual void GetUser(::google::protobuf::RpcController* controller,
const GetUserRequest* request,
UserResponse* response,
::google::protobuf::Closure* done) = 0;
};

第三层:网络通信层(Transport Layer),这一层通常自己实现

1
2
3
4
5
6
7
8
9
10
11
12
13
// gRPC 网络通信层
class GrpcTransport {
public:
// 建立连接
bool Connect(const std::string& endpoint);
// 发送请求
bool SendRequest(const std::string& method_name,
const std::string& serialized_data);
// 接收响应
std::string ReceiveResponse();
// 处理网络错误、超时、重试等
void HandleErrors();
};

使用 grpc + protobuf 的完整流程

Protocol Buffers 是一种接口定义语言(IDL)和高效的序列化框架,它提供了跨语言数据结构服务接口定义能力。

1
2
3
Protocol Buffers = 
├── 接口定义语言 (IDL) // 定义数据结构和服务契约
└── 序列化框架 // 提供高效的二进制序列化

gRPC 是基于 Protobuf 构建的一个高性能 RPC 框架,基于 HTTP/2 协议构建,但不仅仅 “协议” 本身,而是一个 “面向服务的通信框架”。专为微服务设计。

层级 技术
传输层 TCP
应用层协议 HTTP/2
序列化格式 Protocol Buffers
RPC 框架 gRPC(封装了上述三层)

而 Protobuf 本身还可以作为许多其他系统(如消息队列、API 网关、配置管理等)的基础数据定义格式,基础用法如下:

1
2
3
1. 用 .proto 定义接口以后,
2. 使用 .protoc 配合对应框架的插件直接生成代码
3. 将代码代码添加进项目中,在项目中直接使用生成的类。

步骤 1:编写 .proto 文件(定义服务契约)

首先序列化生成数据结构(.proto文件不依赖任何特定编程语言),通常写作:

1
2
3
4
5
6
7
8
9
syntax = "proto3";
package example;

service Calculator {
rpc Add(AddRequest) returns (AddResponse);
}

message AddRequest { int32 a = 1; int32 b = 2; }
message AddResponse { int32 result = 1; }

步骤 2:用 protoc 生成代码

1
protoc --cpp_out=. calculator.proto -> calculator.pb.h, calculator.pb.cc

再利用插件生成 grpc 服务框架(插件保证了 protobuf 可以为不同用途生成不同代码)

1
2
protoc --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin.exe calculator.proto 
-> calculator.grpc.pb.h, calculator.grpc.pb.cc

输出文件:

  • calculator.pb.h/cc → 数据结构
  • calculator.grpc.pb.h/cc →服务接口(Stub + Service)

步骤 3 :在项目中使用生成代码:

客户端:通过 Stub 发起远程调用;

服务端:继承 Service 类并实现具体方法;


rpc 的使用
https://dxblacksmith.github.io/2026/01/30/rpc 的使用/
作者
DxBlackSmith
发布于
2026年1月30日
许可协议