protobuf的流程:1、创建proto项目,使用cmake配置对proto编译;2、创建proto中抽象service的具体实现,启动grpc服务。3、启动客户端
1、创建proto文件
syntax = "proto3";
package math;
service calculator {
rpc sum(request) returns (reply) {}
}
message request {
int32 addend = 1;
int32 additive_term = 2;
}
message reply {
int32 result = 1;
}
set(CMAKE_PREFIX_PATH ${UTILS_ROOT} ${CMAKE_PREFIX_PATH})//使用grpc的根目录
find_package(Protobuf CONFIG REQUIRED)
find_package(gRPC CONFIG REQUIRED)
find_package(Threads)
#
# Protobuf/Grpc source files
#
set(PROTO_FILES
calculator.proto
)
#
# Add Library target with protobuf sources
#
add_library(http_proto ${PROTO_FILES})
target_link_libraries(http_proto
PUBLIC
protobuf::libprotobuf
gRPC::grpc
gRPC::grpc++
)
target_include_directories(http_proto PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
#
# Compile protobuf and grpc files in myproto target to cpp
#
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
protobuf_generate(TARGET http_proto LANGUAGE cpp)
protobuf_generate(TARGET http_proto LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}")
2、创建grpc服务
先实现proto中的service
class CalcuServiceImpl final : public math::calculator::Service {
//grpc::ServerContext *context输入的上下文
// const math::request *request输入的protocol buffer参数
// math::reply *reply输出的protocol buffer参数
grpc::Status sum(grpc::ServerContext *context, const math::request *request,
math::reply *reply) override {
std::cout << "Server: sum for \\""<< request->addend()<<" + "<<request->additive_term() << "\\"." << std::endl;
reply->set_result(request->addend() + request->additive_term());
return grpc::Status::OK;
}
};
然后创建grpc服务
std::string server_address("0.0.0.0:5000");
CalcuServiceImpl service;//1、创建我们的服务实现类 CalcuServiceImpl 的一个实例。
grpc::ServerBuilder builder;//2、创建工厂 ServerBuilder 类的实例。
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());//3、指定要用于使用生成器的 AddListeningPort() 方法侦听客户端请求的地址和端口;InsecureServerCredentials是指不安全的方式。
// Register "service" as the instance through which we'll communicate with
// clients. In this case it corresponds to an *synchronous* service.
builder.RegisterService(&service);
// Finally assemble the server.
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());// 4、构建器上调用 BuildAndStart() ,为我们的服务创建并启动RPC服务器。
std::cout << "Server listening on " << server_address << std::endl;
// Wait for the server to shutdown. Note that some other thread must be
// responsible for shutting down the server for this call to ever return.
server->Wait();//5、在服务器上调用 Wait() 进行阻塞等待,直到进程被终止或调用 Shutdown() 。
target_link_libraries(http_server
PRIVATE
Threads::Threads
nlohmann_json::nlohmann_json
# BOOST::boost
http_proto
PUBLIC
protobuf::libprotobuf
gRPC::grpc
gRPC::grpc++
)
3、创建客户端
#include <grpc/grpc.h>
#include <grpcpp/create_channel.h>
#include "calculator.grpc.pb.h"
class calcuClient {
public:
calcuClient(std::shared_ptr<grpc::Channel> channel)
: stub_(math::calculator::NewStub(channel)) {}
int sum(const int a, const int b) {
math::request req;
req.set_addend(a);//request的成员变量
req.set_additive_term(b);
math::reply reply;
grpc::ClientContext context;
grpc::Status status = stub_->sum(&context, req, &reply);
if (status.ok()) {
return reply.result();
} else {
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return -1;
}
}
private:
std::unique_ptr<math::calculator::Stub> stub_;//存根是啥?
};
#include "calcu_client.h"
int main(int argc, char **argv) {
std::string server_address("127.0.0.1:5000");
calcuClient calcu(
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()));
int result = calcu.sum(1, 2);
std::cout << "calcu received: " << result << std::endl;
return 0;
}