目录
rpc基本工作流程
RPC(Remote Procedure Call,远程过程调用)是一种计算机通信协议,它允许一台计算机(客户端)通过网络调用另一台计算机(服务器)上的函数或方法,而无需了解底层网络技术的细节。
简单来说, RPC 的核心思想是 " 像调用本地函数一样调用远程函数**",它隐藏了网络通信的复杂性(如数据传输、** 序列化 、寻址等),让开发者可以更专注于业务逻辑。
存根(Stub)类的作用
存根(Stub)类是一种关键组件,它扮演着 "代理" 或 "中间层" 的角色,简化了客户端与远程服务之间的通信过程。
-
本地代理:Stub 类在客户端侧提供与远程服务完全一致的方法接口,客户端无需知道服务的具体位置和通信细节。
-
数据处理:接收客户端的调用参数,将其序列化为网络传输格式(如 protobuf、JSON)。接收远程服务返回的结果,反序列化为客户端可直接使用的格式。
-
网络通信:负责与远程服务建立连接、发送请求、接收响应,处理超时、错误等异常情况。
++工作流程++
-
客户端调用本地 Stub:客户端通过调用本地的 Stub(存根)类中的方法发起请求,传入相应参数。
-
参数序列化:Stub 将调用的方法名、参数等信息转换为可在网络上传输的格式(如二进制、JSON、Protobuf 等)。
-
网络传输:客户端通过网络将序列化后的数据发送给服务器。
-
服务器 Stub 处理:服务器端的 Stub 接收请求,将数据反序列化为本地可理解的格式。
-
调用本地服务:服务器 Stub 调用实际的本地函数或方法,执行相应逻辑。
-
返回结果:服务器将执行结果通过同样的流程(序列化→网络传输→反序列化)返回给客户端 Stub,最终客户端得到结果。
RPC 与 HTTP 接口(如 RESTful API)的区别在于:RPC 更注重 "函数调用" 的语义,通常更高效(二进制协议为主);而 HTTP 接口更偏向资源访问,协议可读性强(文本协议为主)。实际开发中可根据需求选择合适的通信方式。
brpc
brpc 是百度开源的一款高性能、低延迟的 RPC 框架,全称为 "Baidu RPC",主要用于构建分布式系统中的高性能服务通信层。它支持多种协议(如 HTTP、protobuf、thrift 等),并针对高并发、低延迟场景进行了优化,广泛应用于百度内部的大规模分布式系统。
特点:
-
基于 C++ 开发,提供简洁的 API,集成流程简单。
-
与 protobuf 无缝结合,通过 .proto 文件定义服务接口,自动生成代码。
应用场景:
-
高并发、低延迟的分布式服务(如微服务架构)。
-
需要跨语言通信的系统(结合 protobuf )。
-
对性能和稳定性要求严格的后端服务(如搜索引擎、大数据处理)
Protocol Buffers(protobuf)具备强大的跨语言能力,protobuf 的跨语言特性主要体现在:
语言无关的接口定义:使用.proto文件定义数据结构(message)和服务(service),这种定义方式与具体编程语言无关。
protobuf 编译器(protoc)可以为多种编程语言生成对应的代码(序列化 / 反序列化逻辑、数据访问类等)。目前官方支持的语言包括:
C++、Java、Python
Go、Ruby、C#、PHP、Dart
此外还有社区支持的更多语言(如 JavaScript、Rust、Swift 等)
++跨语言通信示例:++
定义一个.proto文件(语言无关)
用 protoc 分别生成 Java 和 Python 代码
Java 程序创建数据并序列化
通过网络将二进制数据发送给 Python 程序
Python 程序反序列化并读取数据
++brpc使用流程++
1.定义服务接口(如用protobuf中的service关键字)
2.生成客户端和服务端的框架代码
3.服务端实现接口逻辑,客户端通过sub调用远程服务
4.配置服务器地址,协议类型,超时时间等参数并启动服务
brpc使用示例
++1.编写main.proto文件++
syntax="proto3";
package xg;
//这个选项设置为true时,protoc会为我们生成.proto文件中定义的服务(service)生成通用的C++服务框架代码
//包括服务接口类和存根类
option cc_generic_services=true;
message EchoRequest{
string message=1;
}
message EchoResponse{
string message=1;
}
service EchoService{
rpc Echo(EchoRequest) returns (EchoResponse);
}
编译.proto文件,生成main.pb.h和main.pb.cc文件
protoc --cpp_out=. main.proto
通过service定义的EchoService服务,主要生成了如下两个了类:EchoService和EchoService_Stub
EchoService这个类中有一个Echo虚函数,和main.proto文件对应。这个类需要服务端实现,我们需要定义一个类继承自EchoService,并重写Echo这个方法,也就是实现内部的业务处理逻辑。
这个Echo函数的参数中,有两个参数:request和response,表示对请求request进行处理完成后,将结果再写入到response中,最后发送给客户端。

EchoService_Stub这个类是客户端使用的存根(stub)类,也是客户端进行远程调用的类。这个类也实现了一个Echo函数,客户端调用Echo方法 向服务器发起请求,获取响应。就好像是客户端在本地调用服务器的方法一样。

在这两个类中,Echo方法的参数都一样,上面解释了request和response参数,接下来解释controller和done参数。
::PROTOBUF_NAMESPACE_ID::RpcController* controller和::google::protobuf::Closure* done这两个类型是protobuf内部自己实现的。部分源码如下:
namespace google {
namespace protobuf {
class PROTOBUF_EXPORT Closure {
public:
Closure() {}
virtual ~Closure();
virtual void Run() = 0;
};
inline Closure* NewCallback(void (*function)());//回调函数
class PROTOBUF_EXPORT RpcController {
bool Failed();
std::string ErrorText() ;
}
}
}
-
RpcController的作用:我们在进行rpc请求的时候,是没有返回值的,返回类型是void。这个类的作用就是判断rpc请求是否出错(Failed接口),如果出错,出错原因是什么(ErrorText接口)。
-
Closure的作用:
由于对于请求的业务处理,不一定是在Echo方法中的,也就是说Echo方法执行结束不代表业务处理完成,所以此时就无法构造响应。所以在这个类中有一个run方法,当我们将业务处理完成,响应构造好之后再调用run方法,就可以将响应发送给客户端了。
-
对于客户端这边: 这个类在异步请求的时候会使用到,如果是同步请求不会涉及到。所谓的异步请求是指我们的rpc操作是异步执行的。当客户端收到响应,对于响应该如何处理?所以这个类支持我们设置一个回调函数,来进行响应的处理。客户端收到响应后,就会根据我们设置的回调函数自动进行处理。
-
对于服务器这边: 由于对于请求的业务处理,不一定是在Echo方法中的,也就是说Echo方法执行结束不代表业务处理完成,所以此时就无法构造响应。所以在这个类中有一个run方法,当我们将业务处理完成,响应构造好之后再调用run方法,就可以将响应发送给客户端了。
-
++2.服务器代码编写++
-
创建rpc服务子类继承pb中的EchoService服务类,并实现内部的业务处理逻辑(Echo)。
-
创建rpc服务器类,搭建服务器。
-
向服务器类中添加子服务对象。
-
启动服务器
#include <iostream>
#include <string>
#include <butil/logging.h> //brpc中的日志输出模块
#include <brpc/server.h>
#include "main.pb.h"//1.创建子类继承自EchoService类,并完成业务处理
class EchoServicelmp:public xg::EchoService
{
public:
EchoServicelmp(){}
~EchoServicelmp(){}
void Echo(google::protobuf::RpcController* controller,
const ::xg::EchoRequest* request,
::xg::EchoResponse* response,
::google::protobuf::Closure* done)
{
brpc::ClosureGuard rpc_guard(done);//RAII思想,析构时会调用done->run()
std::cout<<"收到消息:"<<request->message()<<std::endl;
std::string str=request->message()+"这是响应!!!";
response->set_message(str);
//done->run();
}
};int main(int argc,char* argv[])
{
logging::LoggingSettings settings;
settings.logging_dest=logging::LoggingDestination::LOG_TO_NONE;//关闭brpc的日志输出
logging::InitLogging(settings);
//2.构造服务器对象
brpc::Server server;
//向服务器对象中,新增EchoService服务
EchoServicelmp echo_service;
int ret=server.AddService(&echo_service,brpc::ServiceOwnership::SERVER_DOESNT_OWN_SERVICE);
if(ret==-1)
{
std::cout<<"添加 echo_service服务失败"<<std::endl;
return -1;
}
//3.启动服务器
brpc::ServerOptions options;//配置服务器的启动参数,如超时时间
options.idle_timeout_sec=-1;//连接超时时间,超时后会自动关闭连接,-1表示一直等待
options.num_threads=1;//线程数量
ret=server.Start(8080,&options);
if(ret==-1)
{
std::cout<<"服务器启动失败"<<std::endl;
return 2;
}
server.RunUntilAskedToQuit();//休眠等待运行的结束
return 0;
}
++3.客户端代码编写++
-
创建通信信道
-
实例化pb中的EchoService_Stub类
-
调用EchoService_Stub类中对应的接口发起rpc请求
-
获取响应,进行处理
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <brpc/channel.h>
#include "main.pb.h"
// 同步请求
// int main(int argc, char *argv[])
// {
// // 1.构造channel信道对象,连接服务器
// brpc::ChannelOptions options;
// options.connect_timeout_ms = -1; // 连接超时时间
// options.timeout_ms = -1; // rpc请求等待超时时间
// options.max_retry = 3; // 请求重试次数
// options.protocol = "baidu_std"; // 序列化协议,默认使用baidu_std// brpc::Channel channel;
// int ret = channel.Init("127.0.0.1:8080", &options);
// if (ret == -1)
// {
// std::cout << "信道初始化失败" << std::endl;
// return -1;
// }// // 2.构造EchoService_Stub对象,用于rpc调用
// xg::EchoService_Stub echo_stub(&channel);
// xg::EchoRequest req;
// req.set_message("hello world");// // RpcController 是 protobuf 定义的抽象类,用于控制 RPC 调用的上下文
// // brpc 中通过其实现类 brpc::Controller 扩展了更多功能(如设置超时、获取远程地址等)
// brpc::Controller ctl; // 控制器,用于控制brpc调用的上下文(如超时、错误信息、元数据等)
// xg::EchoResponse resp;
// echo_stub.Echo(&ctl, &req, &resp, nullptr); // 同步请求
// if (ctl.Failed() == true)
// {
// std::cout << "rpc调用失败: " << ctl.ErrorText() << std::endl;
// return -2;
// }
// std::cout << "收到响应:" << resp.message() << std::endl;
// return 0;
// }void callback(brpc::Controller *ctl, xg::EchoResponse *resp)
{
std::unique_ptrbrpc::Controller ctl_guard(ctl);
std::unique_ptrxg::EchoResponse resp_guard(resp);
if (ctl_guard->Failed() == true)
{
std::cout << "rpc调用失败: " <<ctl_guard->ErrorText() << std::endl;
return;
}
std::cout << "收到响应:" << resp_guard->message() << std::endl;
}// 异步请求
int main(int argc, char *argv[])
{
// 1.构造channel信道对象,连接服务器
brpc::ChannelOptions options;
options.connect_timeout_ms = -1; // 连接超时时间
options.timeout_ms = -1; // rpc请求等待超时时间
options.max_retry = 3; // 请求重试次数
options.protocol = "baidu_std"; // 序列化协议,默认使用baidu_stdbrpc::Channel channel; int ret = channel.Init("127.0.0.1:8080", &options); if (ret == -1) { std::cout << "信道初始化失败" << std::endl; return -1; } // 2.构造EchoService_Stub对象,用于rpc调用 xg::EchoService_Stub echo_stub(&channel); xg::EchoRequest req; req.set_message("hello world"); // RpcController 是 protobuf 定义的抽象类,用于控制 RPC 调用的上下文 // brpc 中通过其实现类 brpc::Controller 扩展了更多功能(如设置超时、获取远程地址等) brpc::Controller *ctl = new brpc::Controller(); // 控制器,用于控制brpc调用的上下文(如超时、错误信息、元数据等) xg::EchoResponse *resp = new xg::EchoResponse(); // 异步请求 auto closure = google::protobuf::NewCallback(callback, ctl, resp); echo_stub.Echo(ctl, &req, resp, closure); std::cout<<"异步调用结束"<<std::endl; std::this_thread::sleep_for(std::chrono::seconds(3)); return 0;
}