RPC是Remote Procedure Call的简称,中文叫远程过程调用。
gRPC是由 google开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言。
一.编译gRPC
操作系统:windows 10
Qt:5.12.10 MinGW64
CMake:3.13.3
NASM:2.16
这里因为项目需要,编译MinGW64版本的gRPC。Qt安装完成后将下列路径添加到环境变量:
D:\Qt\Qt5.12.10\Tools\mingw730_64\bin
D:\Qt\Qt5.12.10\5.12.10\mingw73_64\bin
1.克隆源码
grpc源码地址:https://github.com/grpc/grpc
git clone git@github.com:grpc/grpc.git
grpc源码下载完后,找到源码根目录下的.gitmodules文件,文件中是grpc编译所需要的子模块,将文件中的url由https地址改为ssh地址,即将https://替换为git@,将.com/替换为.com: 不这么做的话,很多子模块都会下载失败。
替换完成后的文件如下所示:
[submodule "third_party/abseil-cpp"]path = third_party/abseil-cppurl = git@github.com:abseil/abseil-cpp.git[submodule "third_party/benchmark"]path = third_party/benchmarkurl = git@github.com:google/benchmark[submodule "third_party/bloaty"]path = third_party/bloatyurl = git@github.com:google/bloaty.git[submodule "third_party/boringssl-with-bazel"]path = third_party/boringssl-with-bazelurl = git@github.com:google/boringssl.git[submodule "third_party/cares/cares"]path = third_party/cares/caresurl = git@github.com:c-ares/c-ares.git[submodule "third_party/envoy-api"]path = third_party/envoy-apiurl = git@github.com:envoyproxy/data-plane-api.git[submodule "third_party/googleapis"]path = third_party/googleapisurl = git@github.com:googleapis/googleapis.git[submodule "third_party/googletest"]path = third_party/googletesturl = git@github.com:google/googletest.git[submodule "third_party/libuv"]path = third_party/libuvurl = git@github.com:libuv/libuv.git[submodule "third_party/opencensus-proto"]path = third_party/opencensus-protourl = git@github.com:census-instrumentation/opencensus-proto.git[submodule "third_party/opentelemetry"]path = third_party/opentelemetryurl = git@github.com:open-telemetry/opentelemetry-proto.git[submodule "third_party/protobuf"]path = third_party/protobufurl = git@github.com:protocolbuffers/protobuf.git[submodule "third_party/protoc-gen-validate"]path = third_party/protoc-gen-validateurl = git@github.com:envoyproxy/protoc-gen-validate.git[submodule "third_party/re2"]path = third_party/re2url = git@github.com:google/re2.git[submodule "third_party/xds"]path = third_party/xdsurl = git@github.com:cncf/xds.git[submodule "third_party/zlib"]path = third_party/zliburl = git@github.com:madler/zlib# When using CMake to build, the zlib submodule ends up with a# generated file that makes Git consider the submodule dirty. This# state can be ignored for day-to-day development on gRPC.ignore = dirty
接着下载子模块
cd grpcgit submodule update --init#如果某个子模块下载失败,则可多次执行下方命令git submodule update --recursive
2.CMake构建
在grpc目录下新建mingw64文件夹,打开CMake,选择源码路径和构建路径
点击Configure按钮,在弹出框中选择MinGW Makefiles,点击Finish按钮
配置完成,显示Configuring done。需要注意的是必须安装NASM,否则会Configure失败
点击Generate按钮,生成Makefile文件,显示Generating done。记住图中的几个路径,是gRPC最终安装的位置
3.编译
以管理员身份打开Qt 5.12.10(MinGW 7.3.0 64-bit),因为gPRC安装的路径在C盘,不用管理员身份可能会安装失败,提示如下错误:
CMake Error at cmake_install.cmake:36 (file):
file cannot create directory: C:/Program Files (x86)/grpc/lib. Maybe need
administrative privileges.
进入mingw64目录
mingw32-make
我这编译的时候遇到了3个错误
①D:\grpc\src\core\lib\event_engine\tcp_socket_utils.cc:279:64: error: invalid conversion from ‘const void*’ to ‘PVOID {aka void*}’ [-fpermissive]
inet_ntop(addr->sa_family, ip, ntop_buf, sizeof(ntop_buf)) != nullptr) {
解决方法:打开tcp_socket_utils.cc,将ip强制转换为void *
inet_ntop(addr->sa_family, (void *)ip, ntop_buf, sizeof(ntop_buf)) != nullptr) {
②D:\grpc\src\core\lib\event_engine\windows\iocp.cc:143:46: error: ‘WSA_FLAG_NO_HANDLE_INHERIT’ was not declared in this scope
wsa_socket_flags | WSA_FLAG_NO_HANDLE_INHERIT);
^~~~~~~~~~~~~~~~~~~~~~~~~~
D:\grpc\src\core\lib\event_engine\windows\iocp.cc:143:46: note: suggested alternative: ‘UNW_FLAG_NHANDLER’
wsa_socket_flags | WSA_FLAG_NO_HANDLE_INHERIT);
解决方法:打开iocp.cc,将WSA_FLAG_NO_HANDLE_INHERIT改为0x80
DWORD IOCP::WSASocketFlagsInit() { DWORD wsa_socket_flags = WSA_FLAG_OVERLAPPED; /* WSA_FLAG_NO_HANDLE_INHERIT may be not supported on the older Windows versions, see https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx for details. */ SOCKET sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, wsa_socket_flags | 0x80); if (sock != INVALID_SOCKET) { /* Windows 7, Windows 2008 R2 with SP1 or later */ wsa_socket_flags |= 0x80; closesocket(sock); } return wsa_socket_flags;}
之所以这样改,是因为枚举WSA_FLAG_NO_HANDLE_INHERIT的值就是0x80,如下图所示
③D:/grpc/third_party/protobuf/src/google/protobuf/stubs/mutex.h:124:29: error: temporary of non-literal type ‘google::protobuf::internal::CallOnceInitializedMutex’ in a constant expression
constexpr WrappedMutex() {}
解决方法:这是由于protobuf的版本太高导致的,需手动下载protobuf-all-3.16.3,拷贝到./grpc/third_party/protobuf中,重新编译即可
4.安装
mingw32-make install
二.调用gRPC
grpc编译完后,在C:\Program Files (x86)\grpc目录下有编译好的grpc的应用程序、库文件、头文件。将地址C:\Program Files (x86)\grpc\bin添加到环境变量
1.编写.proto文件,生成cpp文件
新建文件helloworld.proto,输入如下内容
syntax = "proto3";package helloworld;// 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 greetingsmessage HelloReply { string greeting = 1;}
打开cmd,进入helloworld.proto文件所在目录,依次执行如下命令
protoc.exe ./helloworld.proto --cpp_out=./protoc.exe ./helloworld.proto --plugin=protoc-gen-grpc="C:/Program Files (x86)/grpc/bin/grpc_cpp_plugin.exe" --grpc_out=./
生成如下四个pb文件
helloworld.pb.h
helloworld.pb.cc
helloworld.grpc.pb.h
helloworld.grpc.pb.cc
2.客户端
在Qt中新建控制台工程GRPC_Client,将上面的四个pb文件添加到工程中,main.cpp修改为如下所示
#include #include #include #include #include #include "helloworld.grpc.pb.h"using grpc::Channel;using grpc::ClientContext;using grpc::Status;using helloworld::Greeter;using helloworld::HelloReply;using helloworld::HelloRequest;class GreeterClient {public: GreeterClient(std::shared_ptr channel) : stub_(Greeter::NewStub(channel)) {} // Assembles the client's payload, sends it and presents the response back // from the server. std::string SayHello(const std::string& user) { // Data we are sending to the server. HelloRequest request; request.set_name(user); // Container for the data we expect from the server. HelloReply 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. Status status = stub_->SayHello(&context, request, &reply); // Act upon its status. if (status.ok()) { return reply.greeting(); } else { std::cout << status.error_code() << ": " << status.error_message() << std::endl; return "RPC failed"; } }private: std::unique_ptr stub_;};int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); GreeterClient greeter( grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials())); std::string user("world"); std::string reply = greeter.SayHello(user); std::cout << "Greeter received: " << reply << std::endl; return a.exec();}
3.服务端
在Qt中新建控制台工程GRPC_Server,将上面的四个pb文件添加到工程中,main.cpp修改为如下所示
#include #include #include #include #include #include #include #include "helloworld.grpc.pb.h"using grpc::Server;using grpc::ServerBuilder;using grpc::ServerContext;using grpc::Status;using helloworld::Greeter;using helloworld::HelloReply;using helloworld::HelloRequest;// Logic and data behind the server's behavior.class GreeterServiceImpl final : public Greeter::Service { Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override { std::string prefix("Hello "); reply->set_greeting(prefix + request->name()); return Status::OK; }};void RunServer() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; grpc::EnableDefaultHealthCheckService(true); grpc::reflection::InitProtoReflectionServerBuilderPlugin(); 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 <Wait();}int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); RunServer(); return a.exec();}
4.pro文件配置
GRPC_Client.pro和GRPC_Server.pro中都要添加如下内容
GRPC_HOME="C:/Program Files (x86)/grpc"INCLUDEPATH += $$GRPC_HOME/includeLIBS += -L$$GRPC_HOME/lib -lgrpc++ -lgrpc -lgpr -lgrpc_plugin_support -lgrpc_unsecure -lgrpc++_alts \-lgrpc++_error_details -lgrpc++_reflection -lgrpc++_unsecure -lgrpcpp_channelz -laddress_sorting \-lcares -labsl_bad_any_cast_impl -labsl_bad_optional_access -labsl_bad_variant_access -labsl_civil_time \-labsl_cordz_info -labsl_cord -labsl_cordz_functions -labsl_cordz_handle -labsl_cord_internal \-labsl_cordz_sample_token -labsl_exponential_biased -labsl_flags -labsl_flags_commandlineflag \-labsl_flags_commandlineflag_internal -labsl_flags_config -labsl_flags_internal -labsl_flags_marshalling \-labsl_flags_parse -labsl_flags_private_handle_accessor -labsl_flags_program_name -labsl_flags_reflection \-labsl_flags_usage -labsl_flags_usage_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_hash \-labsl_city -labsl_hashtablez_sampler -labsl_log_severity -labsl_low_level_hash -labsl_periodic_sampler \-labsl_random_internal_pool_urbg -labsl_random_internal_seed_material -labsl_random_internal_randen_hwaes_impl \-labsl_random_distributions -labsl_random_internal_distribution_test_util -labsl_random_internal_platform \-labsl_random_internal_randen -labsl_random_internal_randen_hwaes -labsl_random_internal_randen_slow \-labsl_random_seed_gen_exception -labsl_random_seed_sequences -labsl_raw_hash_set -labsl_scoped_set_env \-labsl_spinlock_wait -labsl_status -labsl_statusor -labsl_str_format_internal -labsl_strerror -labsl_symbolize \-labsl_failure_signal_handler -labsl_examine_stack -labsl_stacktrace -labsl_leak_check \-labsl_debugging_internal -labsl_demangle_internal -labsl_strings -labsl_strings_internal -labsl_malloc_internal \-labsl_raw_logging_internal -labsl_throw_delegate -labsl_time -labsl_time_zone -labsl_int128 -labsl_base -lre2 \-lupb -lprotobuf -llibprotoc -lzlib.dll -lssl -lcrypto -ldbghelpLIBS += -lWS2_32 -lAdvapi32 -lbcryptDEFINES += _WIN32_WINNT=0x600
注:GRPC_HOME=“C:/Program Files (x86)/grpc” 路径加引号的原因是路径中存在空格
5.运行
先运行GRPC_Server,再运行GRPC_Client,结果如下所示
参考链接:https://blog.csdn.net/u014340533/article/details/125539126
原文链接:https://blog.csdn.net/caoshangpa/article/details/128402625