https://github.com/brpc/brpc/tree/master/example/echo_c%2B%2B
这里学习下brpc的example:echo-c++。先学会使用brpc,载了解了brpc的基本特性之后,再去深入研究。
https://github.com/brpc/brpc/blob/master/docs/cn/client.md
无论是client还是server,均使用gflags
解析命令行参数。例如:
DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
这定义了一个名称为timeout_ms
的命令行参数,默认值是100
,帮助信息为最后一个字符串参数。定义好之后,在main函数中通过如下语句解析命令行参数:
GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true);
之后可以使用FLAGS_timeout_ms
(给timeout_ms加上FLAGS_
前缀) 来获取此变量的值。看来gflags挺便利的。
// A Channel represents a communication line to a Server. Notice that
// Channel is thread-safe and can be shared by all threads in your program.
brpc::Channel channel;
client首先创建了一个brpc::Channel
,翻译下注释:Channel是与Server通信的通道。Channel时thread-safe的,可以被多个线程共享。
接下来对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;
}
接着将Channel传递给Stub类,这里涉及到protobuf service的相关知识,可以移步这里.
// 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);
通常并不直接使用Channel,而是把Channel传递给一个stub service,注意stub也可以被多个线程共享。
最后,通过Stub的Echo接口发送请求,并接收响应。
example::EchoRequest request;
example::EchoResponse response;
brpc::Controller cntl;
request.set_message("hello world");
// 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();
}
实际上,Stub::Echo最终会调用Channel::CallMethod,这是protobuf生成service时自动生成的代码:
void EchoService_Stub::Echo(::google::protobuf::RpcController* controller,
const ::example::EchoRequest* request,
::example::EchoResponse* response,
::google::protobuf::Closure* done) {
channel_->CallMethod(descriptor()->method(0),
controller, request, response, done);
}
// Call `method' of the remote service with `request' as input, and
// `response' as output. `controller' contains options and extra data.
// If `done' is not NULL, this method returns after request was sent
// and `done->Run()' will be called when the call finishes, otherwise
// caller blocks until the call finishes.
void CallMethod(const google::protobuf::MethodDescriptor* method, google::protobuf::RpcController* controller,
const google::protobuf::Message* request,
google::protobuf::Message* response,
google::protobuf::Closure* done);
protobuf的service生成的框架代码决定了,客户端要给Stub类传递一个Channel,Stub会调用Channel的CallMethod。因此client需要实现Channel::CallMethod。
client的命令行参数protocol默认使用的协议为baidu_std
, 该协议的定义在src/brpc/options.proto
:
https://github.com/brpc/brpc/blob/master/docs/cn/baidu_std.md