gRPC的使用(cpp)

gRPC是google开源的一套实现rpc调用的框架,支持多种语言,并且比较易用,其数据传输是通过google自家的protobuf来序列化的,下面我们通过改写gRPC的example来实现获取远程host内存的功能。

【gRPC的使用(cpp)】例子中的文件目录结构如下
./examples/cpp/sysproc ./examples/cpp/sysproc/sysproc_server.cc ./examples/cpp/sysproc/Makefile ./examples/protos/sysproc.proto

1.先定义protobuf文件 文件描述了接口的参数结构和接口结构
sysproc.proto
syntax = "proto3"; service SysProcManager { rpc getSysProc (NullMessage) returns (SysProc) {} }message NullMessage {}message SysProc { int32 memfree = 1; };

由于这里的接口必须需要参数,所以我们增加了一个Null类型的消息
我们定义了一个SysProc消息结构用于getSysProc rpc方法的返回值,service的名字叫SysProcManager
服务器端代码 sysproc_service.cc
#include "sysproc.grpc.pb.h" #include #include #include #include extern "C" { #include }using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; // Logic and data behind the server's behavior. class SysProcServiceImpl final : public SysProcManager::Service { Status getSysProc(ServerContext* context, const NullMessage* request, SysProc * reply) override { int memFree = 0; struct sysinfo info; sysinfo(&info); memFree = (int)(info.freeram); reply->set_memfree(memFree); return Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); SysProcServiceImpl service; ServerBuilder builder; // Listen on the given address without any authentication mechanism. builder.AddListeningPort(server_address, grpc::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 server(builder.BuildAndStart()); 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(); }int main(int argc, char** argv) { RunServer(); return 0; }

SysProcServiceImpl先定义了一个Service类继承自我们刚刚定义的protobuf文件编译产生的grpc的文件SysProcManager::Service,并实现getSysProc,在后面的Makefile文件中会看到编译的过程
通过ServiceBuilder创建一个builder并监听服务器端口,然后注册我们刚刚写的Service类,这时候就wait处理客户端请求就好了
sysproc_client.cc
#include #include #include #include #include "sysproc.grpc.pb.h"using grpc::Channel; using grpc::ClientContext; using grpc::Status; class SysProcClient { public: //创建客户端类,该类通过一个SysProcManager(protobuf定义的Service)的stub来和服务器端进行通信 SysProcClient(std::shared_ptr channel) : stub_(SysProcManager::NewStub(channel)) {}// Assembles the client's payload, sends it and presents the response back // from the server. int getSysProc() { // Data we are sending to the server. NullMessage request; // Container for the data we expect from the server. SysProc reply; // Context for the client. It could be used to convey extra information to // the server and/or tweak certain RPC behaviors. ClientContext context; // The actual RPC. //stub调用生成的接口调用service Status status = stub_->getSysProc(&context, request, &reply); // Act upon its status. if (status.ok()) { return reply.memfree(); } else { std::cout << status.error_code() << ": " << status.error_message() << std::endl; return -1; } } private: std::unique_ptr stub_; }; int main(int argc, char** argv) { // Instantiate the client. It requires a channel, out of which the actual RPCs // are created. This channel models a connection to an endpoint (in this case, // localhost at port 50051). We indicate that the channel isn't authenticated // (use of InsecureChannelCredentials()). //创建一个chanel用于定义一个和服务器端的网络连接,传给client的stub SysProcClient sysproc_client(grpc::CreateChannel( "localhost:50051", grpc::InsecureChannelCredentials())); int reply = sysproc_client.getSysProc(); std::cout << "Client received: " << reply << std::endl; return 0; }

Makefile:
HOST_SYSTEM = $(shell uname | cut -f 1 -d_) SYSTEM ?= $(HOST_SYSTEM) CXX = g++ CPPFLAGS += `pkg-config --cflags protobuf grpc` CXXFLAGS += -std=c++11 ifeq ($(SYSTEM),Darwin) LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ -lgrpc++_reflection\ -ldl else LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\ -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\ -ldl endif PROTOC = protoc GRPC_CPP_PLUGIN = grpc_cpp_plugin GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`PROTOS_PATH = ../../protosvpath %.proto $(PROTOS_PATH)all: system-check sysproc_client sysproc_serversysproc_client: sysproc.pb.o sysproc.grpc.pb.o sysproc_client.o $(CXX) $^ $(LDFLAGS) -o $@sysproc_server: sysproc.pb.o sysproc.grpc.pb.o sysproc_server.o $(CXX) $^ $(LDFLAGS) -o $@.PRECIOUS: %.grpc.pb.cc %.grpc.pb.cc: %.proto $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<.PRECIOUS: %.pb.cc %.pb.cc: %.proto $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $ /dev/null && echo true || echo false) ifeq ($(HAS_PROTOC),true) HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) endif HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)SYSTEM_OK = false ifeq ($(HAS_VALID_PROTOC),true) ifeq ($(HAS_PLUGIN),true) SYSTEM_OK = true endif endifsystem-check: ifneq ($(HAS_VALID_PROTOC),true) @echo " DEPENDENCY ERROR" @echo @echo "You don't have protoc 3.0.0 installed in your path." @echo "Please install Google protocol buffers 3.0.0 and its compiler." @echo "You can find it here:" @echo @echo "https://github.com/google/protobuf/releases/tag/v3.0.0" @echo @echo "Here is what I get when trying to evaluate your version of protoc:" @echo -$(PROTOC) --version @echo @echo endif ifneq ($(HAS_PLUGIN),true) @echo " DEPENDENCY ERROR" @echo @echo "You don't have the grpc c++ protobuf plugin installed in your path." @echo "Please install grpc. You can find it here:" @echo @echo "https://github.com/grpc/grpc" @echo @echo "Here is what I get when trying to detect if you have the plugin:" @echo -which $(GRPC_CPP_PLUGIN) @echo @echo endif ifneq ($(SYSTEM_OK),true) @false endif

运行 先运行服务器sysproc_server,再运行sysproc_client就能看到结果的

    推荐阅读