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就能看到结果的