当前位置: 首页 > article >正文

brpc的简单使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 大体流程
  • 一、编写.proto文件
  • 二、服务端搭建
    • 1.继承EchoService创建一个子类,并重写业务方法
    • 2.构造服务器对象
    • 3.向服务器对象中,新增EchoService服务
    • 4.启动服务器
  • 三、客户端搭建
    • 1.构造Channel信道,连接服务器
    • 2.构造存根对象,用于rpc调用
    • 3.进行rpc调用 --同步调用
    • 4.异步调用


前言

使用brpc简单搭建一个echo服务。


大体流程

Rpc调用实现样例:
服务端:
1.创建rpc服务子类继承pb中的EchoService服务类,并实现内部的业务接口逻辑
2.创建rpc服务器类,搭建服务器
3. 向服务器类中添加 rpc子服务对象 – 告诉服务器收到什么请求用哪个接口处理
4.启动服务器
客户端:
1.创建网络通信信道
2.实例化pb中的EchoService Stub类对象
3.发起rpc请求,获取响应进行处理

一、编写.proto文件

定义两个message结构体 代表请求和响应。
定义一个servicer 服务。
使用 protoc --cpp_out./ main生成.cc和.h文件

syntax="proto3";

package example;

option cc_generic_services = true;

message EchoRequest{
    string message = 1;
}

message EchoResponse{
    string message = 1;
}

service EchoService{
    rpc Echo(EchoRequest) returns (EchoResponse);
}

二、服务端搭建

1.继承EchoService创建一个子类,并重写业务方法

重写的方法就是.proto文件中声明的,这个方法有四个参数,req和resp就不解释了,从req中获取数据,进行业务处理,并把结果写入到resp中。

其中,第一个参数RpcController,这是一个上下文管理类,主要是用来判断请求是否ok。
而第四个参数Closure,在服务器端当响应处理完毕后,需要显示效用这个类中run方法,告诉brpc响应已经处理完了,结果已经写入到resp中,可以给客户端进行响应了。
而为了防止用户忘记调用run,我们可以使用ClosureGuard来管理这个closure对象,他会帮我们调用run方法。

class EchoServiceImpl : public example::EchoService{
public:
    EchoServiceImpl(){}
    ~EchoServiceImpl(){}

    //重写Echo方法
    void Echo(google::protobuf::RpcController* controller,
                         const ::example::EchoRequest* request,
                         ::example::EchoResponse* response,
                         ::google::protobuf::Closure* done){
        
        brpc::ClosureGuard rpc_guard(done);
        std::cout << "收到消息:" << request->message() << std::endl;

        std::string str = request->message() + "--这是响应!!";
        response->set_message(str);
    }
};

2.构造服务器对象

构造一个服务器用于网络通信。

brpc::Server server;

3.向服务器对象中,新增EchoService服务

将Echoservice服务注册进服务器中,当指定的服务请求到来时,调用指定的服务处理函数,这里的SERVER_DOESNT_OWN_SERVICE代表服务添加失败后,服务器不帮忙释放这个对象。

 EchoServiceImpl echo_service;
    int ret = server.AddService(&echo_service,brpc::ServiceOwnership::SERVER_DOESNT_OWN_SERVICE);
    if (ret == -1) {
        std::cout << "添加Rpc服务失败!\n";
        return -1;
    }

4.启动服务器

启动服务器需要填写监听端口和一个ServerOptions对象.
这个对象主要是设置服务器相关选项,多长时未发送连接相关活动就断开连接,io的线程数量等。

 //4.启动服务器
    brpc::ServerOptions options;
    options.idle_timeout_sec = -1;  //多长时间没有连接相关事件则关闭连接 -1为永不关闭
    options.num_threads = 1;    //io线程数量
    ret = server.Start(8085,&options);
    if (ret == -1) {
        std::cout << "添加Rpc服务失败!\n";
        return -1;
    }
    server.RunUntilAskedToQuit();// 运行服务器,直到请求退出

三、客户端搭建

1.构造Channel信道,连接服务器

brpc对连接进行了更细粒度的划分,在一个连接上可以建立多个信道,而多个信道他们底层使用的是同一个连接。用户只需要使用channel来与服务器通信,从而抽象了网络细节。

同样的在与服务器建立连接时,也需要传入一个Channeloptions对象,

	brpc::ChannelOptions options;
	options.connect_timeout_ms = -1;    //连接超时时间
	options.timeout_ms = -1;    //请求超时时间
	options.max_retry = 3;  //最大重传次数
	options.protocol = "baidu_std"; //网络通信协议
	brpc::Channel channel;
	int ret = channel.Init("127.0.0.1:8085",&options);
	if (ret == -1) {
	    std::cout << "初始化信道失败!\n";
	    return -1;
    }

2.构造存根对象,用于rpc调用

example::EchoService_Stub stub(&channel);

3.进行rpc调用 --同步调用

同步调用Echo会阻塞等待响应的返回。
同样的,在客户端的调用中也有四个参数。
第一个参数Controller是用于判断请求是否Ok.
第四个参数就不同了,在服务器中第四个参数是为了告知brpc业务已经处理完毕,可以进行返回响应。客户端的第四个参数主要是为了支持异步调用。

    example::EchoRequest req;
    req.set_message("你好,lkm");
    example::EchoResponse resp;
    brpc::Controller cntl;
    stub.Echo(&cntl,&req,&resp,nullptr);
    if(cntl.Failed() == true){
        std::cout << "Rpc调用失败:" << cntl.ErrorText() << std::endl;
        return -1;
    }
    std::cout << "收到响应: " << resp.message() << std::endl;

4.异步调用

第四个参数是一个Closure对象,它可以设置一个回调函数,当响应返回后调用设置的回调函数进行处理。
需要注意的是,由于Echo现在是异步调用,所有他在调用完后就会立即返回,所以为了防止作用域问题,我们需要把resp和Controller在堆上创建。

void callback(brpc::Controller* cntl,example::EchoResponse* resp)
{
    std::unique_ptr<brpc::Controller> cntl_guard(cntl);
    std::unique_ptr<example::EchoResponse> resp_guard(resp);
    if (cntl->Failed() == true) {
        std::cout << "Rpc调用失败:" << cntl->ErrorText() << std::endl;
        return;
    }
    std::cout << "收到响应: " << resp->message() << std::endl;
}

 example::EchoRequest req;
    req.set_message("你好,lkm");
    example::EchoResponse *resp = new example::EchoResponse();
    brpc::Controller *cntl = new brpc::Controller();
    google::protobuf::Closure* closure = google::protobuf::NewCallback(callback,cntl,resp);   //这里设置回调函数
    stub.Echo(cntl,&req,resp,closure);

    std::cout << "rpc调用请求已发送" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3));

http://www.kler.cn/news/312420.html

相关文章:

  • 力扣 11.盛最多水的容器
  • 重修设计模式-结构型-桥接模式
  • Python编码系列—Python组合模式:构建灵活的对象组合
  • Suno新上线Covers翻唱新 - 实现音频风格任意转换
  • Spring Boot-跨服务事务管理问题
  • DNS解析流程
  • 系统架构-面向对象
  • 【Python】探索 Blinker:Python 进程内信号/事件分发系统
  • uniapp vue3 梯形选项卡组件
  • springboot调用python脚本实现ocr图片文字识别功能
  • Maven踩坑——父模块生命周期的操作会被子模块继承
  • 零信任安全架构--持续验证
  • Android 12系统源码_窗口管理(八)WindowConfiguration的作用
  • 基于SpringBoot+Vue+MySQL的养老院管理系统
  • SSMP+ajax实现广告系统的分页效果
  • 有关JS下隐藏的敏感信息
  • 【C++篇】~类和对象(中)
  • 【C++】STL----stack和queue常见用法
  • 请求响应-05.请求-日期参数JSON参数
  • Vue2时间轴组件(TimeLine/分页、自动顺序播放、暂停、换肤功能、时间选择,鼠标快速滑动)
  • HarmonyOS 应用获取公钥和 MD5 指纹签名信息
  • MySQL——数据库的高级操作(二)用户管理(4)修改用户密码
  • 第6天:趋势轮动策略开发(年化18.8%,大小盘轮动加择时)
  • 基于STM32设计的水渠闸门远程控制系统(华为云IOT)(226)
  • 14_Python面向对象
  • 【LeetCode】每日一题 2024_9_17 公交路线(BFS)
  • Effective Java 学习笔记45-48 Stream
  • VS code 查看 ${workspaceFolder} 目录指代路径
  • 设计模式-行为型模式-解释器模式
  • Python 解析 Charles JSON Session File (.chlsj)