grpc的编译及简单使用
1.grpc相关参考文档
-
grpc 主页: https://grpc.io/
-
grpc 文档: https://grpc.io/docs/
-
grpc 编译包1: https://packages.grpc.io/
-
grpc 编译包2: https://pkgs.org/download/grpc
-
grpc github地址: https://github.com/grpc/grpc
-
编译gRPC C++整套指导说明在《grpc cpp编译》
-
对于如何将gRPC作为依赖添加到你的C++项目中, 可参考通用说明《开始使用gRPC C++》
2.使用cmake编译安装gRPC
本文下载grpc是使用大陆外服务器下载grpc项目源码v1.32.X分支及其子模块submodule,总共1G左右,下载用时5分钟左右;大陆内用户可能首先需要解决下载问题。该章节主要翻译自gRPC C++快速开始--HelloWorld示例。
2.1. 前置条件
-
确保安装CMake且版本最好大于3.13
检查cmake版本
1$ cmake --version在Linux下, 现有系统级别的cmake版本太低,可以通过一下脚本在本地目录安装更新的cmake版本。源码安装cmake等详细信息可参看文章CMake升级安装版本到3.17以上。
123$ wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.17.0/cmake-3.17.0-Linux-x86_64.sh$ sh cmake-linux.sh -- --skip-license --prefix=/usr$ rm cmake-linux.sh -
Linux编译工具
1$ sudo yum install -y build-essential autoconf libtool pkg-config -
配置环境变量(可选操作)
选择一个目录作为本地安装路径,这里认为环境变量 MY_INSTALL_DIR 作为目录路径;
123456# 构建路径$ export MY_INSTALL_DIR=/usr/local/# 确保目录已存在$ mkdir -p $MY_INSTALL_DIR# 将本地bin目录增加到path环境变量中$ export PATH="$PATH:$MY_INSTALL_DIR/bin"
2.2. Linux/Unix下使用
在git克隆grpc项目后,在该目录下运行--recursive或update子模块submodules命令;如果想要编译动态库.so文件,运行cmake时添加-DBUILD_SHARED_LIBS=ON
.
1 2 3 4 5 6 7 8 9 |
$ mkdir -p cmake/build $ cd cmake/build $ cmake -DgRPC_INSTALL=ON \ -DgRPC_BUILD_TESTS=OFF \ -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \ ../.. # cmake ../.. -DCMAKE_INSTALL_PREFIX=/usr $ make $ make install |
2.3. 依赖库管理
对于解决依赖项,gRPC的CMAKE构建系统有两个选择。CMake可以为你编译构建依赖库,或者寻找已安装到操作系统的库文件并使用他们构建gRPC。执行方式通过CMake中 gRPC_
- module - 一起编译第三方依赖库和gRPC。这些依赖库源码是通过gRPC的git子模块获取到的。
- package - 使用系统中已存在的依赖库,并将外部依赖库拷贝进行编译。这些可能来自当前编译系统的包管理器,也可以使用CMake的CMAKE_INSTALL_PREFIX选项提前安装并指定他们。
例如,你可以设置gRPC_CARES_PROVIDER=module
, 这样CMake将在构建gRPC之前构建c-ares。另一方面,如果设置gRPC_CARES_PROVIDER=package
, CMake将会寻找已经安装到系统的c-ares并复制它来构建gRPC。
2.4. 构建够安装gRPC
如下步骤通过CMake安装gRPC:
- 设置-DgRPC_INSTALL=ON
- 构建安装路径,通过CMAKE_INSTALL_PREFIX变量指定。
如果CMake是v3.13或更高,需要通过"module"模式来构建gRPC的第三方依赖库并且一键安装。而如果构建小于1.27版本的gRPC或使用小于3.13的CMake,需要选择"package"而不是"module"模式来构建第三方依赖。这就需要你确保当前系统的第三方依赖库可用。如下示例表示在安装gRPC之前,如何通过CMake安装依赖库。
1 2 3 4 5 6 7 8 9 10 11 |
# 所有gRPC的第三方依赖库需要已安装成功 $ cmake ../.. -DgRPC_INSTALL=ON \ -DCMAKE_BUILD_TYPE=Release \ -DgRPC_ABSL_PROVIDER=package \ -DgRPC_CARES_PROVIDER=package \ -DgRPC_PROTOBUF_PROVIDER=package \ -DgRPC_RE2_PROVIDER=package \ -DgRPC_SSL_PROVIDER=package \ -DgRPC_ZLIB_PROVIDER=package $ make $ make install |
2.5. protoc注意事项
默认情况gRPC使用protocol buffers,你需要使用protoc编译器生成根服务器和客户端节点代码;如果使用gRPC源码安装并遍历下载了子模块,Makefile将查看是否已安装protoc并自动编译第三方protoc。
3.grpc的C++库使用
3.1. gRPC例子HelloWorld
-
编译范例HelloWorld
- 从安装目录中运行示例/cpp/helloworld/cmake/build
1234567# 进入grpc项目中cd examples/cpp/helloworld# 准备构建,这里一定确保cmake版本正确$ mkdir -p cmake/build$ pushd cmake/build$ cmake ../..$ make -j -
运行服务端
1$ ./greeter_server -
从不同的终端运行客户端程序,显示如下说明已运行成功
123456$ ./greeter_clientGreeter received: Hello world//14: failed to connect to all addresses// Greeter received: RPC failed//如果出现该问题,说明没有连接成功;查看是否服务端开启,且端口号和客户端一致;查看是否依赖项问题; -
升级gRPC服务
现在看下服务端如何用外部的一些方法更新应用,同时可用于客户端; gRPC服务里用使用了protocol buffers,我们可以找到很多文章解释如何在.proto文件定义服务;现在你需要知道的是,服务端和客户端都需要SayHello()的RPC函数方式,客户端通过它传递HelloRequest类型参数到服务端,服务端返回HelloResponse类型参数。通过examples/protos/helloworld.proto路径查看如下定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; } |
然后添加方法SayHelloAgain(), 以及相同的请求和响应类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} // Sends another greeting rpc SayHelloAgain (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; } |
- 重新生成代码
在使用新服务方法前,需要重新编译更新下proto文件。然后从目录examples/cpp/helloworld/cmake/build
下运行
1 |
$ make -j |
这样重新生成了helloworld.pb.{h,cc}和helloworld.grpc.pb.{h,cc}, 其中包含了服务端和客户端类文件, 以及类的传递、序列化、以及获取的请求和响应类型。 实际是执行编译helloworld.proto文件为cpp等文件,类似protoc --cpp_out=. helloworld.proto
,并引用其编译为二进制文件;创建grpc文件,采用命令protoc --grpc_out . --cpp_out . -I . --plugin=protoc-gen-grpc=/usr/local/bin/grpc_cpp_plugin abc.proto
;
- 升级并运行程序
尽管上一步新生成了新代码,但仍需要在example应用中人工修改代码,执行调用新方法;
-
服务端
从example根目录下打开cpp/helloworld/greeter_server.cc,执行如下方法:
12345678910class GreeterServiceImpl final : public Greeter::Service {Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override {// ...}Status SayHelloAgain(ServerContext* context, const HelloRequest* request,HelloReply* reply) override {std::string prefix("Hello again ");reply->set_message(prefix + request->name());return Status::OK;}};- 客户端
现在protobuf根库中新的SayHelloAgain()已经可用。我们需要在GreeterClient中按照相同方式,完成SayHello()和SayHelloAgain()函数,文件greeter_client.cc中:
12345678910111213141516171819202122class GreeterClient {public:// ...std::string SayHello(const std::string& user) {// ...}std::string SayHelloAgain(const std::string& user) {// Follows the same pattern as SayHello.HelloRequest request;request.set_name(user);HelloReply reply;ClientContext context;// Here we can use the stub's newly available method we just added.Status status = stub_->SayHelloAgain(&context, request, &reply);if (status.ok()) {return reply.message();} else {std::cout << status.error_code() << ": " << status.error_message()<< std::endl;return "RPC failed";}}- 最终在主函数中运行新方法:
12345678int main(int argc, char** argv) {// ...std::string reply = greeter.SayHello(user);std::cout << "Greeter received: " << reply << std::endl;reply = greeter.SayHelloAgain(user);std::cout << "Greeter received: " << reply << std::endl;return 0;}
- 运行执行
在examples/cpp/helloworld/cmake/build目录中执行如下命令:
1 2 3 4 5 6 7 8 |
$ make -j # 运行服务端程序 $ ./greeter_server # 在不同终端运行如下客户端程序 $ ./greeter_client # 看到如下输出 Greeter received: Hello world Greeter received: Hello again world |
如果想要异步客户端和服务端,可以在源码目录中看到greeter_async_server,greeter_async_client等代码文件。
3.2. 例子RouteGuide
读者可以参看gRPC中文手册中C++教程进行操作。这里不进一步展开。该程序主要是路线指引,借助json文件进行计算;
赞赏微信赞赏
支付宝赞赏