简介

gRPC是一种由Google推出的RPC框架,开源,跨语言,跨平台,高性能。

gRPC次要是基于protobuf设计实现的。

本文次要介绍如何在C++中应用gRPC。

装置

不像Java,配置一个maven插件,增加相应的maven依赖,就能够搭建好gRPC环境。

C++个别须要下载gRPC的源码,而后编译构建,失去须要的库文件,protoc编译器,以及gRPC插件。

  1. 下载源码
git clone --recurse-submodules -b v1.41.0 https://github.com/grpc/grpccd grpc
  1. 创立cmake构建目录
mkdir -p cmake/buildcd cmake/build
  1. 生成makefile
cmake -DgRPC_INSTALL=ON \      -DgRPC_BUILD_TESTS=OFF \      -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \      ../..

MY_INSTALL_DIR变量指定了最终生成的库文件,protoc的装置地位,linux零碎个别为/usr/local

  1. 构建
make -j
  1. 装置
make install

此命令会依据第三部指定的MY_INSTALL_DIR的,将构建进去的库装置到相应的地位。比方protoc就放在${MY_INSTALL_DIR}/bin目录下,

头文件就放在${MY_INSTALL_DIR}/include/grpc目录下。

当然,执行上述命令须要装置g++, cmake, git等工具。

HelloWorld

应用gRPC首先须要写proto文件,形容rpc,供客户端和服务端应用。

  1. proto文件接口定义

hello.proto

// protobuf版本syntax = "proto3";// rpc申请的定义message HelloRequest {  optional string name = 1;}// rpc响应的定义message HelloReply {  optional string message = 1;}// rpc服务的定义,两个函数service HelloWorld {  rpc SayHello (HelloRequest) returns (HelloReply) {}  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}}
  1. 服务端

proto仅定义了接口,还须要在服务端写程序,实现rpc。server.cc

#include "hello.grpc.pb.h"#include <string>#include <grpcpp/grpcpp.h>// rpc服务实现class HelloServiceImpl : public HelloWorld::Service{    grpc::Status SayHello(grpc::ServerContext* context, const HelloRequest* req, HelloReply* rsp)    {        std::cout << "Request SayHello From " << context->peer() << std::endl;        rsp->set_message("hello " + req->name() + "!");        return grpc::Status::OK;    }    grpc::Status SayHelloAgain(grpc::ServerContext* context, const HelloRequest* req, HelloReply* rsp)    {        std::cout << "Request SayHelloAgain From " << context->peer() << std::endl;        rsp->set_message("hello " + req->name() + " again!!");        return grpc::Status::OK;    }};// 启动运行int main(int argc, char** argv){    std::string address("localhost:5000");    HelloServiceImpl service;    grpc::ServerBuilder builder;    builder.AddListeningPort(address, grpc::InsecureServerCredentials());    builder.RegisterService(&service);    std::unique_ptr<grpc::Server> server(builder.BuildAndStart());    std::cout << "Server Listening on port: " << address << std::endl;    server->Wait();    return 0;}
  1. 客户端

客户端调用服务端的,client.cc

#include "hello.grpc.pb.h"#include <string>#include <iostream>#include <sstream>#include <grpcpp/grpcpp.h>// 客户端class HelloClient{public:    HelloClient(std::shared_ptr<grpc::Channel> channel) : _stub(HelloWorld::NewStub(channel))    {}    std::string SayHello(const std::string& name)    {        HelloRequest req;        HelloReply rsp;        req.set_name(name);        grpc::ClientContext context;        grpc::Status status = _stub->SayHello(&context, req, &rsp);        if(status.ok())        {            return rsp.message();        }        else        {             std::ostringstream out;             out << status.error_code() << " : " << status.error_message();             return out.str();        }    }    std::string SayHelloAgain(const std::string& name)    {        HelloRequest req;        HelloReply rsp;        req.set_name(name);        grpc::ClientContext context;        grpc::Status status = _stub->SayHelloAgain(&context, req, &rsp);        if(status.ok())        {            return rsp.message();        }        else        {            std::ostringstream out;            out << status.error_code() << " : " << status.error_message();            return out.str();        }    }private:    std::unique_ptr<HelloWorld::Stub> _stub;};// 调用rpcint main(int argc, char** argv){    std::string address("0.0.0.0:5000");    HelloClient client(grpc::CreateChannel(address, grpc::InsecureChannelCredentials()));    std::string name("bazel");    std::cout << client.SayHello(name) << std::endl;    std::cout << client.SayHelloAgain(name) << std::endl;    return 0;}

编译运行

  1. proto编译
protoc --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` hello.proto

上述命令会生成hello.pb.h/cc和hello.grpc.pb.h/cc

  1. 服务端
g++ -std=c++11 \    `pkg-config --cflags protobuf grpc` \    `pkg-config --libs protobuf grpc++` \    -framework CoreFoundation \ // 仅MacOS须要加    -o server \    hello.pb.cc hello.grpc.pb.cc server.cc

其中pkg-config --cflags protobuf grpc指定了头文件的地位,pkg-config --libs protobuf grpc++指定了库文件的地位,-framework CoreFoundation 仅在MacOS中须要增加,这是因为grpc的abseil的time库在MacOS下用的是CoreFoundation中的

而后./server运行

  1. 客户端
g++ -std=c++11 \    `pkg-config --cflags protobuf grpc` \    `pkg-config --libs protobuf grpc++`      -framework CoreFoundation \ // 仅MacOS须要加    -o client \     hello.pb.cc hello.grpc.pb.cc client.cc

而后./client运行

参考

Quick start | C++ | gRPC

gRPC C++ 入门教程