gRPC 的安装与使用 1 2 OS: Arch Linux on Windows 10 x86_64 Kernel: 5.15.90.1-microsoft-standard-WSL2
安装 官网教程
我选择安装在 $HOME/.local
这个目录中。
准备构建工具 首先需要安装 cmake
, 版本不能低于 3.13
, 可以使用包管理器安装。
接着就是构建 gRPC 的其他工具了 build-essential
, autoconf
, libtool
, pkg-config
在 Debian/Ubuntu
中直接使用包管理安装即可,在 Arch Linux
中,build_essential
在仓库中的名字是 base-devel
。
安装 gRPC 从 Github 上将 grpc
和它的子模块都克隆下来:
1 git clone --recurse-submodules -b v1.56.0 --depth 1 --shallow-submodules https://github.com/grpc/grpc
接着就可以开始构建 gRPC
了, 构建 gRPC
的同时还会构建 Protocol Buffers
。
1 2 3 4 5 6 7 8 9 10 $ cd grpc $ mkdir -p cmake/build $ pushd cmake/build $ cmake -DgRPC_INSTALL=ON \ -DgRPC_BUILD_TESTS=OFF \ -DCMAKE_INSTALL_PREFIX=$HOME /.local \ ../.. $ make -j 4 $ make install $ popd
这样就安装好了, 安装目录在 $HOME/.local
下,有bin
, include
, lib
, share
四个部分,把 bin
文件夹添加到环境变量里 :
1 export PATH=$HOME/bin:/usr/local/bin:$PATH
重启终端就能直接使用 $HOME/.local/bin
下的文件。
使用 使用 cmake
来构建一个简单的 gRPC Demo 来体验。
客户端向服务端发送包含了一个数字的请求,服务端返回一个数组,这个数组使用请求中的数字填充,大小也是请求中的数字。
CMakeLists 1 2 3 4 5 6 7 8 9 10 . ├── client │ └── client.cpp ├── CMakeLists.txt ├── proto │ ├── CppProto │ └── Messages.proto ├── README.md └── server └── server.cpp
Messages.proto
生成的文件放到 CppProto
中
CMakeLists.txt
的编写还是非常复杂的,官方给的例子中也是一层套一层。
主要是 gRPC 相关的库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 cmake_minimum_required (VERSION 3.20 .0 )project (grpc_test LANGUAGES CXX)set (CMAKE_CXX_STANDARD 20 )set (CMAKE_C_STANDARD 11 )set (CMAKE_EXPORT_COMPILE_COMMANDS YES)set (protobuf_MODULE_COMPATIBLE TRUE )find_package (Protobuf CONFIG REQUIRED)message (STATUS "Using protobuf ${Protobuf_VERSION}" )set (_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)set (_REFLECTION gRPC::grpc++_reflection)if (CMAKE_CROSSCOMPILING) find_program (_PROTOBUF_PROTOC protoc)else () set (_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)endif ()find_package (gRPC CONFIG REQUIRED)message (STATUS "Using gRPC ${gRPC_VERSION}" )set (_GRPC_GRPCPP gRPC::grpc++)if (CMAKE_CROSSCOMPILING) find_program (_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)else () set (_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)endif ()include_directories ("./" )include_directories (${PROJECT_SOURCE_DIR} /proto/CppProto)file (GLOB proto_srcs_hdrs ${PROJECT_SOURCE_DIR} /proto/CppProto/*.cc)add_library (rg_grpc_proto ${proto_srcs_hdrs} )target_link_libraries (rg_grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF} )file (GLOB server_src ${PROJECT_SOURCE_DIR} /server/*.cpp)file (GLOB client_src ${PROJECT_SOURCE_DIR} /client/*.cpp)add_executable (server ${server_src} )target_link_libraries (server rg_grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF} )add_executable (client ${client_src} )target_link_libraries (client rg_grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF} )
Protocol Buffers Messages.proto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 syntax = "proto3"; package Test; service GetService { rpc GetVec(Request) returns (Reponse) {} } message Request { int32 num = 1; } message Reponse { repeated int32 vec = 1; }
server server.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include "Messages.grpc.pb.h" #include <grpcpp/security/server_credentials.h> #include <grpcpp/server_builder.h> #include <grpcpp/server_context.h> #include <grpcpp/support/status.h> #include <iostream> #include <memory> #include <grpcpp/grpcpp.h> class GetServiceImpl final : public Test::GetService::Service { auto GetVec (grpc::ServerContext *context, const Test::TestRequest *req, Test::TestReponse *rep) -> grpc::Status { int num = req->num (); std::cout << "request value : " << req->num () << "\n" ; for (int i = 0 ; i< num; ++i) { rep->add_vec (num); } return grpc::Status::OK; } };auto RunServer () -> void { std::string server_address ("0.0.0.0:50051" ) ; GetServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort (server_address, grpc::InsecureServerCredentials ()); builder.RegisterService (&service); std::unique_ptr<grpc::Server> server (builder.BuildAndStart()) ; std::cout << "Server listening on " << server_address << "\n" ; server->Wait (); }int main () { RunServer (); }
client client.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include "Messages.grpc.pb.h" #include "Messages.pb.h" #include <format> #include <grpcpp/client_context.h> #include <grpcpp/create_channel.h> #include <grpcpp/impl/channel_interface.h> #include <grpcpp/security/credentials.h> #include <iostream> #include <memory> class GetServiceClient {public : GetServiceClient (std::shared_ptr<grpc::ChannelInterface> channel) : stub_ (Test::GetService::NewStub (channel)) {} auto GetVec (int num) { Test::TestRequest req; Test::TestReponse rep; req.set_num (num); grpc::ClientContext context; grpc::Status status = stub_->GetVec (&context, req, &rep); if (status.ok ()) { std::cout << "reponse status : OK\nreponse value : " ; for (auto v : rep.vec ()) { std::cout << v << " " ; } std::cout << "\n" ; } else { std::cout << std::format("reponse status : {} \n" , status.error_message ()); } } private : std::unique_ptr<Test::GetService::Stub> stub_; };int main () { auto channel = grpc::CreateChannel ("localhost:50051" , grpc::InsecureChannelCredentials ()); GetServiceClient client (channel) ; while (true ) { int num = 0 ; std::cin >> num; client.GetVec (num); } }
测试