• 【brpc学习实战二】brpc client构建基本流程


    client基本概念及学习指南

    https://github.com/luozesong/brpc/blob/master/docs/cn/client.md

    一、编写proto

    这里与服务一致,实际开发中需要双端共同确定proto内容;

    二、初始化channel

    rpc channel可以视为socket编程中的client对象
    定义一个channel,Channel可以被所有线程共用,你不需要为每个线程创建独立的Channel,也不需要用锁互斥。不过Channel的创建和Init并不是线程安全的,请确保在Init成功后再被多线程访问,在没有线程访问后再析构

    三、初始化channel options

    填充连接相关的的参数如超时、协议、最大重试次数、负载均衡算法等

    四、channel init with options

    初始化channel

    五、初始化自定义service_stub

    protobuf会为我们定义的rpc 函数生成一个xxx_stub用来和服务交互。我们需要用自定义service_stub初始化我们的客户端对象。如果proto没定义rpc 服务,可以用Channel.CallMethod。

    六、发起访问

    一般来说,我们不直接调用Channel.CallMethod,而是通过protobuf生成的桩XXX_Stub,过程更像是“调用函数”。stub内没什么成员变量,建议在栈上创建和使用,而不必new,当然你也可以把stub存下来复用。Channel::CallMethod和stub访问都是线程安全的,可以被所有线程同时访问。
    XXX_Stub stub(&channel);
    stub.some_method(controller, request, response, done);
    这里的some_method为在proto中定义的rpc服务经过编译后得到的抽象接口,像service_stub.ParallelSearchPlans。
    如果我们没定义rpc服务,用brpc内部已定义好的服务时,需要用到callmethod()发起请求。而我们可以通过addchannel组装多个请求,一次调用,可以用在提升服务的性能。下面是一个实际示例

    while (request_num--) {
            pchan.AddChannel(channel, baidu::rpc::DOESNT_OWN_CHANNEL, rpc_call_mapper, rpc_response_merger);
        }
        
        uint64_t logid = UII_GET_LOGID();
        cntl->set_log_id(logid);
        AccessLogGuard access_log_guard(service_name.c_str(), "nshead", req, res, cntl);
    
        pchan.CallMethod(NULL, cntl, req, res, baidu::rpc::DoNothing());
        if (cntl->Failed()) {
            UII_LOG_WARNING("Fail to access service:%s Error:%s", service_name.c_str(), cntl->ErrorText().c_str());
            return -1;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    上面代码使用rpc::DoNothing()实现了一个半同步的请求响应,阻塞到所有的请求返回。

    七、返回处理

    我们发起访问后,可以根据controler调用cntl->Failed()判断请求是否成功。若成功,就可以对res响应进行处理。

    八、基础客户端案例及释义

    // Licensed to the Apache Software Foundation (ASF) under one
    // or more contributor license agreements.  See the NOTICE file
    // distributed with this work for additional information
    // regarding copyright ownership.  The ASF licenses this file
    // to you under the Apache License, Version 2.0 (the
    // "License"); you may not use this file except in compliance
    // with the License.  You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing,
    // software distributed under the License is distributed on an
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    // KIND, either express or implied.  See the License for the
    // specific language governing permissions and limitations
    // under the License.
    
    // A client sending requests to server every 1 second.
    
    #include 
    #include 
    #include 
    #include 
    #include "echo.pb.h"
    
    DEFINE_string(attachment, "", "Carry this along with requests");
    DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
    DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
    DEFINE_string(server, "0.0.0.0:8000", "IP Address of server");
    DEFINE_string(load_balancer, "", "The algorithm for load balancing");
    DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
    DEFINE_int32(max_retry, 3, "Max retries(not including the first RPC)"); 
    DEFINE_int32(interval_ms, 1000, "Milliseconds between consecutive requests");
    
    int main(int argc, char* argv[]) {
        // Parse gflags. We recommend you to use gflags as well.
        GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true);
        
        brpc::Channel channel;
        
        // Initialize the channel, NULL means using default options.
        brpc::ChannelOptions options;
        options.protocol = FLAGS_protocol;
        options.connection_type = FLAGS_connection_type;
        options.timeout_ms = FLAGS_timeout_ms/*milliseconds*/;
        options.max_retry = FLAGS_max_retry;
        if (channel.Init(FLAGS_server.c_str(), FLAGS_load_balancer.c_str(), &options) != 0) {
            LOG(ERROR) << "Fail to initialize channel";
            return -1;
        }
    
        // Normally, you should not call a Channel directly, but instead construct
        // a stub Service wrapping it. stub can be shared by all threads as well.
        example::EchoService_Stub stub(&channel);
    
        // Send a request and wait for the response every 1 second.
        int log_id = 0;
        while (!brpc::IsAskedToQuit()) {
            // We will receive response synchronously, safe to put variables
            // on stack.
            example::EchoRequest request;
            example::EchoResponse response;
            brpc::Controller cntl;
    
            request.set_message("hello world");
    
            cntl.set_log_id(log_id ++);  // set by user
            // Set attachment which is wired to network directly instead of 
            // being serialized into protobuf messages.
            cntl.request_attachment().append(FLAGS_attachment);
    
            // Because `done'(last parameter) is NULL, this function waits until
            // the response comes back or error occurs(including timedout).
            stub.Echo(&cntl, &request, &response, NULL);
            if (!cntl.Failed()) {
                LOG(INFO) << "Received response from " << cntl.remote_side()
                    << " to " << cntl.local_side()
                    << ": " << response.message() << " (attached="
                    << cntl.response_attachment() << ")"
                    << " latency=" << cntl.latency_us() << "us";
            } else {
                LOG(WARNING) << cntl.ErrorText();
            }
            usleep(FLAGS_interval_ms * 1000L);
        }
    
        LOG(INFO) << "EchoClient is going to quit";
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
  • 相关阅读:
    66. SAP ABAP Function Module 的动态调用方式使用方式介绍
    redis介绍和理解
    《Web安全基础》06. 逻辑漏洞&越权
    android鼠标滚轮事件监听方法
    【英语:基础高阶_全场景覆盖表达】K11.口语主题陈述——事物类
    数据结构与算法(三)——递归
    (刘二大人)PyTorch深度学习实践-卷积网络(基础篇)
    查看及测试网络
    面经-框架-事务失效的几种场景
    消失的人!消除视频中不需要的人物
  • 原文地址:https://blog.csdn.net/qq_42936727/article/details/134487904