目录
介绍
brpc 是用 c++语言编写的工业级 RPC 框架,常用于搜索、存储、机器学习、广告、推荐等高性能系统
安装
先安装依赖
apt-get install -y git g++ make libssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libleveldb-dev libgflags-dev
安装brpc
去github上下载https://github.com/apache/brpc.git
依次执行
unzip brpc-master.zip
cd brpc-master
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr .. && cmake --build . -j6
make && sudo make install
使用
示例:
main.proto文件
syntax="proto3";
package example;
option cc_generic_services = true; // 这个选项的功能其实就是 生成框架代码的时候, 内部包含了rpc相关接口的内容
message EchoRequest{
string message = 1;
}
message EchoResponse{
string message = 1;
}
//这是回显服务器的名称
service EchoService{
// EchoRequest参数 EchoResponse返回类型
rpc Echo(EchoRequest) returns (EchoResponse); // 定义rpc接口
}
client.cc文件
#include <brpc/channel.h>
#include <thread>
#include "main.pb.h"
//brpc是同步调用还是异步调用, 是客户端来决定的 -- 明天ai问一下
void callback(brpc::Controller* cntl, ::example::EchoResponse* response){
std::unique_ptr<brpc::Controller> cntl_guard(cntl);
std::unique_ptr<example::EchoResponse> resp_guard(response);
if (cntl->Failed() == true) {
std::cout << "Rpc调用失败: " << cntl->ErrorText() << std::endl;
return;
}
std::cout << "收到响应: " << response->message() << std::endl;
}
int main(int argc, char* argv[])
{
//1. 构造Channel信道, 连接服务器
brpc::ChannelOptions options;
options.connect_timeout_ms = -1; //连接等待超时时间, -1表示一直等待
options.timeout_ms = -1; //rpc请求等待超时时间, -1表示一直等待
options.protocol = "baidu_std"; //序列化协议, 默认使用baidu_std
brpc::Channel channel; //为什么要有这个类? 没有这个类就不能进行通信, 理解为管道
int ret = channel.Init("127.0.0.1:8080", &options); //参数1: 服务器地址 参数2: 客户端连接时的配置
if (ret == -1) {
std::cout << "初始化信道失败! \n";
return -1;
}
//2. 构造EchoService_Stub对象, 用于进行rpc调用
example::EchoService_Stub stub(&channel); //相当于客户端类
//3. 进行Rpc调用
example::EchoRequest req;
req.set_message("你好~比特~!");
//这个Controller提供了很多功能, 其中一个就是辨别返回值的成功或失败
brpc::Controller* cntl = new brpc::Controller();
//如果我们不想同步处理, 即不想等待响应, 希望异步, 就要通过Controller设置回调函数
//注意一个问题: 可能在处理回调函数的时候,如果这个cntl和rsp是栈对象 这个cntl,rsp会被释放掉, 如果这个main函数
//是一个普通的函数,则处理这个回调函数的时候,可能这个函数已经结束了, 这个cntl,rsp已经被释放掉了,这就可能出现错误
example::EchoResponse* rsp = new example::EchoResponse(); //用于接收返回值的
auto clusure = google::protobuf::NewCallback(callback, cntl, rsp);
stub.Echo(cntl, &req, rsp, clusure); //异步调用
// stub.Echo(cntl, &req, rsp, nullptr); //最后一个参数, 如果是异步调用, 则要传参让服务器设置去run, 我们是同步调用, 所以就不用设置了
// if(cntl->Failed() == true) {
// std::cout << "Rpc调用失败: " << cntl->ErrorText() << std::endl;
// return -1;
// }
// std::cout << "收到响应: " << rsp->message() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0; //如果是异步调用, 主函数需要等待, 否则程序可能会直接结束
}
server.cc文件
#include <brpc/server.h>
#include <butil/logging.h>
#include "main.pb.h"
//1. 继承与EchoService创建一个子类, 并实现rpc调用的业务功能
class EchoServiceImpl : public example::EchoService{ //EchoService类是远程调用rpc服务的类 - 就是真正进行sum计算的
public:
// 重写这个虚函数
//RpcController: 返回结果是成功或失败
//request客户端的请求 response服务器要构造的响应
//Closure: 大格局理解 服务端是异步执行的, 将Response的响应设置完了, 再调用run函数, 告诉服务器可以发给客户端响应了
void Echo(google::protobuf::RpcController* controller, const ::example::EchoRequest* request,
::example::EchoResponse* response, ::google::protobuf::Closure* done) //至于这个函数是在业务服务器 主线程还是线程池中执行, 我们并不关心
{
//防止程序员忘记最后调用run函数, 所以用智能指针来管理起来
brpc::ClosureGuard rpc_guard(done);
std::cout << "收到消息:" << request->message() << std::endl;
std::string str = request->message() + "--这是响应!!";
response->set_message(str);
// done->Run() 如果不写上面的guard, 则需要加上这句话
}
};
int main(int argc, char* argv[])
{
// 关闭brpc的默认日志输出
logging::LoggingSettings settings;
settings.logging_dest = logging::LoggingDestination::LOG_TO_NONE;
logging::InitLogging(settings);
//2. 构造服务器对象
brpc::Server server;
//3. 向服务器对象中, 新增EchoService服务
EchoServiceImpl echo_service;
int ret = server.AddService(&echo_service, brpc::ServiceOwnership::SERVER_DOESNT_OWN_SERVICE);
if (ret == -1){
std::cout << "添加Rpc服务失败!\n";
return -1;
}
//参数1: 添加服务, 只有你添加了服务, 服务器才能处理你对应的请求, 和路由很像 类型为Service*, EchoServiceImpl是它的子类
//参数2: 添加服务失败的时候, 服务器是否会删除该对象 因为echo_service是局部变量, 所以不用去释放
//4. 启动服务器
brpc::ServerOptions options; //启动服务器时的配置类
options.idle_timeout_sec = -1; //连接空闲超时时间 - 超时后连接被关闭
options.num_threads = 1; //io线程数量
ret = server.Start(8080, &options);
if (ret == -1) {
std::cout << "启动服务器失败! \n";
return -1;
}
server.RunUntilAskedToQuit(); //服务器一直循环运行
return 0;
}
先用protoc进行编译:
编译运行: