baidu-brpc学习之简单使用实例编写

本文介绍BRPC框架下的RPC服务实现,包括服务端与客户端的代码示例,涉及protobuf消息定义、服务注册与调用流程。同时分享了VS2019远程调试经验及依赖库配置细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

rpc_proto文件:

syntax="proto2";
package example;

option cc_generic_services = true;

//=====service 1
message EchoRequest {
      required string message = 1;
};

message EchoResponse {
      required string message = 1;
};

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


//=====service 2
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  required string name = 1;
}

// The response message containing the greetings
message HelloReply {
  required string message = 1;
}

这里定义了两种服务协议。

server.cpp服务端文件:

#include <cstdio>
#include <gflags/gflags.h>
#include <butil/logging.h>
#include <brpc/server.h>
#include "echo.pb.h"

DEFINE_bool(echo_attachment, true, "Echo attachment as well");
DEFINE_int32(port, 8000, "TCP Port of this server");
DEFINE_int32(idle_timeout_s, -1, "Connection will be closed if there is no "
	"read/write operations during the last `idle_timeout_s'");
DEFINE_int32(logoff_ms, 2000, "Maximum duration of server's LOGOFF state "
	"(waiting for client to close connection before server stops)");

DEFINE_bool(gzip, false, "compress body using gzip");

// Your implementation of example::EchoService
// Notice that implementing brpc::Describable grants the ability to put
// additional information in /status.
namespace example {
	class EchoServiceImpl : public EchoService {
	public:
		EchoServiceImpl() {};
		virtual ~EchoServiceImpl() {};
		virtual void Echo(google::protobuf::RpcController* cntl_base,
			const EchoRequest* request,
			EchoResponse* response,
			google::protobuf::Closure* done) {
			// This object helps you to call done->Run() in RAII style. If you need
			// to process the request asynchronously, pass done_guard.release().
			brpc::ClosureGuard done_guard(done);

			brpc::Controller* cntl =
				static_cast<brpc::Controller*>(cntl_base);

			// The purpose of following logs is to help you to understand
			// how clients interact with servers more intuitively. You should 
			// remove these logs in performance-sensitive servers.
			LOG(INFO) << "Received request[log_id=" << cntl->log_id()
				<< "] from " << cntl->remote_side()
				<< " to " << cntl->local_side()
				<< ": " << request->message()
				<< " (attached=" << cntl->request_attachment() << ")";

			// Fill response.
			response->set_message(request->message());

			// You can compress the response by setting Controller, but be aware
			// that compression may be costly, evaluate before turning on.
			// cntl->set_response_compress_type(brpc::COMPRESS_TYPE_GZIP);

			if (FLAGS_echo_attachment) {
				// Set attachment which is wired to network directly instead of
				// being serialized into protobuf messages.
				cntl->response_attachment().append(cntl->request_attachment());
			}
		}
	};

	//===
	class GreeterImpl : public Greeter {
	public:
		GreeterImpl() {};
		virtual ~GreeterImpl() {};

		void SayHello(google::protobuf::RpcController* cntl_base,
			const HelloRequest* req,
			HelloReply* res,
			google::protobuf::Closure* done) {

			brpc::ClosureGuard done_guard(done);
			brpc::Controller* cntl = static_cast<brpc::Controller*>(cntl_base);

			sleep(10);

			if (FLAGS_gzip) {
				cntl->set_response_compress_type(brpc::COMPRESS_TYPE_GZIP);
			}

			res->set_message("Hello " + req->name());
		}
	};


}  // namespace example



int main(int argc, char* argv[]) {
	// Parse gflags. We recommend you to use gflags as well.
	google::ParseCommandLineFlags(&argc, &argv, true);

	// Generally you only need one Server.
	brpc::Server server;

	// Instance of your service.
	example::EchoServiceImpl echo_service_impl;
	example::GreeterImpl greeter_impl;

	// Add the service into server. Notice the second parameter, because the
	// service is put on stack, we don't want server to delete it, otherwise
	// use brpc::SERVER_OWNS_SERVICE.
	if (server.AddService(&echo_service_impl,
		brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {

		LOG(ERROR) << "Fail to add service";
		return -1;
	}

	if (server.AddService(&greeter_impl,
		brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {

		LOG(ERROR) << "Fail to add service";
		return -1;
	}

	// Start the server.
	brpc::ServerOptions options;
	options.idle_timeout_sec = FLAGS_idle_timeout_s;
	if (server.Start(FLAGS_port, &options) != 0) {

		LOG(ERROR) << "Fail to start EchoServer";
		return -1;
	}

	// Wait until Ctrl-C is pressed, then Stop() and Join() the server.
	server.RunUntilAskedToQuit();
	return 0;
}

client.cpp客户端文件:

#include <cstdio>
#include <gflags/gflags.h>
#include <butil/logging.h>
#include <butil/time.h>
#include <brpc/channel.h>
#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, "127.0.0.1:8000", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
DEFINE_int32(timeout_ms, 20000, "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.
	google::ParseCommandLineFlags(&argc, &argv, true);

	// 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;

	// 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);
	example::Greeter_Stub greeter_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();
		}

		cntl.Reset();
		example::HelloRequest helloRequest;
		example::HelloReply helloReply;

		helloRequest.set_name("xiao hua");
		cntl.set_log_id(log_id++);

		greeter_stub.SayHello(&cntl, &helloRequest, &helloReply, NULL);

		if (!cntl.Failed()) {
			LOG(INFO) << "Received response from " << cntl.remote_side()
				<< " to " << cntl.local_side()
				<< ": " << helloReply.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;
}

这里我是使用VS2019远程调试的,所以就没有Makefile文件。不得不说VS对Linux程序的支持体验真的是越来越好了,感觉可以告别notepad++的时代了。

另外附上程序需要的库依赖项:

各种平台下brpc的编译见github:

https://github.com/apache/incubator-brpc/blob/master/docs/cn/getting_started.md

这里需要注意一点是openssl库的版本使用1.1.0以上的,否则会出现undefined referenced的错误。原因就是之前版本中的许多宏定义在新版本中已经换成了函数,虽然他们的名称是相同的。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值