GRPC编译安装、各种语言插件及测试
复制过程,可能乱了。原笔记地址
官网
编译 安装 官方测试 手写测试 跨语言测试(这里用golang)
一、编译和安装
1.1源码编译安装
git clone GitHub - grpc/grpc: The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) --depth 1 (也可以指定版本 git clone -b RELEASE_TAG_HERE https://github.com/grpc/grpc)
cd grpc
git submodule update --init (这个可能比较慢,我试了全局科学上网,才行。也没多试)
mkdir -p cmake/build
cd cmake/build
cmake ../.. (这个需要点时间)
make
sudo make install
查看生成的编译生成的东西
➜ ls CMakeCache.txt cmake_install.cmake grpc_csharp_plugin grpc_ruby_plugin libgrpc++.a libgrpc.a libupb.a CMakeFiles gRPCConfig.cmake grpc_node_plugin http_archives libgrpc++_alts.a libgrpc_plugin_support.a protos CPackConfig.cmake gRPCConfigVersion.cmake grpc_objective_c_plugin lib libgrpc++_error_details.a libgrpc_unsecure.a third_party CPackSourceConfig.cmake gens grpc_php_plugin libaddress_sorting.a libgrpc++_reflection.a libgrpcpp_channelz.a Makefile grpc_cpp_plugin grpc_python_plugin libgpr.a libgrpc++_unsecure.a libs
上面可以看出几个参见的plugin有:
-rwxr-xr-x 1 bob staff 6.0M 10 31 19:18 grpc_cpp_plugin -rwxr-xr-x 1 bob staff 6.1M 10 31 19:20 grpc_csharp_plugin -rwxr-xr-x 1 bob staff 5.9M 10 31 19:20 grpc_node_plugin -rwxr-xr-x 1 bob staff 6.0M 10 31 19:20 grpc_objective_c_plugin -rwxr-xr-x 1 bob staff 6.1M 10 31 19:20 grpc_php_plugin -rwxr-xr-x 1 bob staff 6.0M 10 31 19:20 grpc_python_plugin -rwxr-xr-x 1 bob staff 5.8M 10 31 19:20 grpc_ruby_plugin
安装protobuf
不要手动安装,不然版本可能和grpc版本不匹配,推荐使用grpc执行git submodule update --init命令后生成的third_party/protobuf里面biany8安装对应的protobuf
cd third_party/protobuf
./autogen.sh 这里第一次执行报错内容如下
test -d third_party/googletest mkdir -p third_party/googletest/m4 autoreconf -f -i -Wall,no-obsolete Can't exec "aclocal": No such file or directory at /usr/local/Cellar/autoconf/2.71/share/autoconf/Autom4te/FileUtils.pm line 274. autoreconf: error: aclocal failed with exit status: 2
解决 brew install automake
再执行 ./autogen.sh 就OK了
./configure --prefix=/usr/local
make (时间较久)
sudo make install
protoc --version可以验证
> protoc --version libprotoc 3.21.6
1.2 mac brew 安装
可以参考官网Quick start | C++ | gRPC
export MY_INSTALL_DIR=$HOME/.local mkdir -p $MY_INSTALL_DIR export PATH="$MY_INSTALL_DIR/bin:$PATH" brew install cmake brew install autoconf automake libtool pkg-config //下面这一步很慢,可能还有失败的,后来终端科学上网才完全OK,有一次没下载全,下面cmake命令会失败 //如果下面这一步试了几次还有失败,可以cd grpc 执行 git submodule update --init git clone --recurse-submodules -b v1.50.0 --depth 1 --shallow-submodules https://github.com/grpc/grpc cd grpc mkdir -p cmake/build pushd cmake/build cmake -DgRPC_INSTALL=ON \ -DgRPC_BUILD_TESTS=OFF \ -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \ ../.. make -j 4 make install popd
二、测试
2.1测试官方示例
$ cd examples/cpp/helloworld $ mkdir -p cmake/build $ pushd cmake/build $ cmake -DCMAKE_PREFIX_PATH=$MY_INSTALL_DIR ../.. $ make -j 4
启动 server
./greeter_server
> $ ./greeter_server [±91091e3 ✓] Server listening on 0.0.0.0:50051
另外一个终端打开执行
./greeter_client
./greeter_client Greeter received: Hello world
更新proto文件
cd examples/protos
vim helloworld.proto
syntax = "proto3"; option java_multiple_files = true; option java_package = "io.grpc.examples.helloworld"; option java_outer_classname = "HelloWorldProto"; option objc_class_prefix = "HLW"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} 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; }
保存后,重新生成grpc代码
cd examples/cpp/helloworld/cmake/build
make -j 8
更新server端代码
greeter_server.cc
class 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; } };
更新client端
greeter_client.cc
class 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"; } }
在client 的main函数里面调用
int 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; }
运行
cd examples/cpp/helloworld/cmake/build
编译 make -j 8
启动server ./greeter_server
./greeter_server Server listening on 0.0.0.0:50051
其他终端测试client
./greeter_client Greeter received: Hello world Greeter received: Hello again world
2.2自己写的测试
创建项目

cmake/common.cmake 是官方的内容,直接复制来就行
https://github.com/grpc/grpc/blob/master/examples/cpp/cmake/common.cmake
2022-11-02 14:32:55时内容如下
# Copyright 2018 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # cmake build file for C++ route_guide example. # Assumes protobuf and gRPC have been installed using cmake. # See cmake_externalproject/CMakeLists.txt for all-in-one cmake build # that automatically builds all the dependencies before building route_guide. cmake_minimum_required(VERSION 3.5.1) if (NOT DEFINED CMAKE_CXX_STANDARD) set (CMAKE_CXX_STANDARD 14) endif() if(MSVC) add_definitions(-D_WIN32_WINNT=0x600) endif() find_package(Threads REQUIRED) if(GRPC_AS_SUBMODULE) # One way to build a projects that uses gRPC is to just include the # entire gRPC project tree via "add_subdirectory". # This approach is very simple to use, but the are some potential # disadvantages: # * it includes gRPC's CMakeLists.txt directly into your build script # without and that can make gRPC's internal setting interfere with your # own build. # * depending on what's installed on your system, the contents of submodules # in gRPC's third_party/* might need to be available (and there might be # additional prerequisites required to build them). Consider using # the gRPC_*_PROVIDER options to fine-tune the expected behavior. # # A more robust approach to add dependency on gRPC is using # cmake's ExternalProject_Add (see cmake_externalproject/CMakeLists.txt). # Include the gRPC's cmake build (normally grpc source code would live # in a git submodule called "third_party/grpc", but this example lives in # the same repository as gRPC sources, so we just look a few directories up) add_subdirectory(../../.. ${CMAKE_CURRENT_BINARY_DIR}/grpc EXCLUDE_FROM_ALL) message(STATUS "Using gRPC via add_subdirectory.") # After using add_subdirectory, we can now use the grpc targets directly from # this build. set(_PROTOBUF_LIBPROTOBUF libprotobuf) set(_REFLECTION grpc++_reflection) if(CMAKE_CROSSCOMPILING) find_program(_PROTOBUF_PROTOC protoc) else() set(_PROTOBUF_PROTOC $
helloworld.proto
syntax = "proto3"; option java_multiple_files = true; option java_package = "io.grpc.examples.helloworld"; option java_outer_classname = "HelloWorldProto"; option objc_class_prefix = "HLW"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloAgain (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.5.1) project(HelloWorld C CXX) include(./cmake/common.cmake) # Proto file get_filename_component(hw_proto "./protos/helloworld.proto" ABSOLUTE) get_filename_component(hw_proto_path "${hw_proto}" PATH) # Generated sources set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.cc") set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.h") set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc") set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h") add_custom_command( OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" COMMAND ${_PROTOBUF_PROTOC} ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" -I "${hw_proto_path}" --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" "${hw_proto}" DEPENDS "${hw_proto}") # Include generated *.pb.h files include_directories("${CMAKE_CURRENT_BINARY_DIR}") # hw_grpc_proto add_library(hw_grpc_proto ${hw_grpc_srcs} ${hw_grpc_hdrs} ${hw_proto_srcs} ${hw_proto_hdrs}) target_link_libraries(hw_grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) foreach(_target greeter_client greeter_server) add_executable(${_target} "${_target}.cc") target_link_libraries(${_target} hw_grpc_proto ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) endforeach()
greeter_server.cc
#include
greeter_client.cc
#include
开始编译
protoc --cpp_out=./ protos/helloworld.proto
protoc --grpc_out=. --plugin=protoc-gen-grpc=which grpc_cpp_plugin protos/helloworld.proto

mkdir build && cd build
cmake ..
make -j 4
运行
./greeter_server Server listening on 0.0.0.0:50051
client连接
./greeter_client Greeter received: Hello world Greeter received: Hello again world
2.3golang作为lient调用
项目结构
├── go.mod
├── go.sum
├── main.go
└── protos
└── helloworld.proto

proto内容 注意go_package
syntax = "proto3"; //option go_package = "path;name"; option go_package = "./protos;pb"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloAgain (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
执行下面两个命令
protoc --go_out=. --go_opt=paths=source_relative protos/helloworld.proto
protoc --go-grpc_out=. --go-grpc_opt=paths=source_relative protos/helloworld.proto
会生成两个文件

main.go
package main import ( pb "awesomeProject1/protos" "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "log" ) func main() { conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) defer conn.Close() if err != nil { log.Fatal(err) } client := pb.NewGreeterClient(conn) reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "test"}) if err != nil { fmt.Println(err) } fmt.Println(reply) }
go run main.go
go run main.go bob@cmbp message:"Hello test"
OK