小言_互联网的博客

Qt中调用gRPC

689人阅读  评论(0)

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: 不这么做的话,很多子模块都会下载失败。
替换完成后的文件如下所示:


  
  1. [submodule "third_party/abseil-cpp"]
  2. path = third_party/abseil-cpp
  3. url = git@github.com:abseil/abseil-cpp.git
  4. [submodule "third_party/benchmark"]
  5. path = third_party/benchmark
  6. url = git@github.com:google/benchmark
  7. [submodule "third_party/bloaty"]
  8. path = third_party/bloaty
  9. url = git@github.com:google/bloaty.git
  10. [submodule "third_party/boringssl-with-bazel"]
  11. path = third_party/boringssl-with-bazel
  12. url = git@github.com:google/boringssl.git
  13. [submodule "third_party/cares/cares"]
  14. path = third_party/cares/cares
  15. url = git@github.com:c-ares/c-ares.git
  16. [submodule "third_party/envoy-api"]
  17. path = third_party/envoy-api
  18. url = git@github.com:envoyproxy/data-plane-api.git
  19. [submodule "third_party/googleapis"]
  20. path = third_party/googleapis
  21. url = git@github.com:googleapis/googleapis.git
  22. [submodule "third_party/googletest"]
  23. path = third_party/googletest
  24. url = git@github.com:google/googletest.git
  25. [submodule "third_party/libuv"]
  26. path = third_party/libuv
  27. url = git@github.com:libuv/libuv.git
  28. [submodule "third_party/opencensus-proto"]
  29. path = third_party/opencensus-proto
  30. url = git@github.com:census-instrumentation/opencensus-proto.git
  31. [submodule "third_party/opentelemetry"]
  32. path = third_party/opentelemetry
  33. url = git@github.com:open-telemetry/opentelemetry-proto.git
  34. [submodule "third_party/protobuf"]
  35. path = third_party/protobuf
  36. url = git@github.com:protocolbuffers/protobuf.git
  37. [submodule "third_party/protoc-gen-validate"]
  38. path = third_party/protoc-gen-validate
  39. url = git@github.com:envoyproxy/protoc-gen-validate.git
  40. [submodule "third_party/re2"]
  41. path = third_party/re2
  42. url = git@github.com:google/re2.git
  43. [submodule "third_party/xds"]
  44. path = third_party/xds
  45. url = git@github.com:cncf/xds.git
  46. [submodule "third_party/zlib"]
  47. path = third_party/zlib
  48. url = git@github.com:madler/zlib
  49. # When using CMake to build, the zlib submodule ends up with a
  50. # generated file that makes Git consider the submodule dirty. This
  51. # state can be ignored for day-to-day development on gRPC.
  52. ignore = dirty

接着下载子模块


  
  1. cd grpc
  2. git submodule update --init
  3. #如果某个子模块下载失败,则可多次执行下方命令
  4. 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


  
  1. DWORD IOCP::WSASocketFlagsInit() {
  2.   DWORD wsa_socket_flags = WSA_FLAG_OVERLAPPED;
  3.   /* WSA_FLAG_NO_HANDLE_INHERIT may be not supported on the older Windows
  4.      versions, see
  5.      https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
  6.      for details. */
  7.   SOCKET sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
  8.                           wsa_socket_flags | 0x80);
  9.   if (sock != INVALID_SOCKET) {
  10.     /* Windows 7, Windows 2008 R2 with SP1 or later */
  11.     wsa_socket_flags |= 0x80;
  12.     closesocket(sock);
  13.   }
  14.   return wsa_socket_flags;
  15. }

之所以这样改,是因为枚举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<std::mutex>' 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,输入如下内容


  
  1. syntax = "proto3";
  2. package helloworld;
  3. // The greeting service definition.
  4. service Greeter {
  5.   // Sends a greeting
  6.   rpc SayHello (HelloRequest) returns (HelloReply) {}
  7. }
  8. // The request message containing the user's name.
  9. message HelloRequest {
  10.   string name = 1;
  11. }
  12. // The response message containing the greetings
  13. message HelloReply {
  14.   string greeting = 1;
  15. }

打开cmd,进入helloworld.proto文件所在目录,依次执行如下命令


  
  1. protoc.exe . /helloworld.proto --cpp_out=./
  2. 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修改为如下所示


  
  1. #include <QCoreApplication>
  2. #include <iostream>
  3. #include <memory>
  4. #include <string>
  5. #include <grpcpp/grpcpp.h>
  6. #include "helloworld.grpc.pb.h"
  7. using grpc::Channel;
  8. using grpc::ClientContext;
  9. using grpc::Status;
  10. using helloworld::Greeter;
  11. using helloworld::HelloReply;
  12. using helloworld::HelloRequest;
  13. class GreeterClient {
  14. public:
  15.     GreeterClient(std::shared_ptr<Channel> channel)
  16.         : stub_(Greeter:: NewStub(channel)) {}
  17.     // Assembles the client's payload, sends it and presents the response back
  18.     // from the server.
  19.     std::string SayHello(const std::string& user) {
  20.         // Data we are sending to the server.
  21.         HelloRequest request;
  22.         request. set_name(user);
  23.         // Container for the data we expect from the server.
  24.         HelloReply reply;
  25.         // Context for the client. It could be used to convey extra information to
  26.         // the server and/or tweak certain RPC behaviors.
  27.         ClientContext context;
  28.         // The actual RPC.
  29.         Status status = stub_-> SayHello(&context, request, &reply);
  30.         // Act upon its status.
  31.         if (status. ok()) {
  32.             return reply. greeting();
  33.         } else {
  34.             std::cout << status. error_code() << ": " << status. error_message()
  35.                       << std::endl;
  36.             return "RPC failed";
  37.         }
  38.     }
  39. private:
  40.     std::unique_ptr<Greeter::Stub> stub_;
  41. };
  42. int main(int argc, char *argv[])
  43. {
  44.     QCoreApplication a(argc, argv);
  45.     GreeterClient greeter(
  46.                 grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));
  47.     std::string user("world");
  48.     std::string reply = greeter. SayHello(user);
  49.     std::cout << "Greeter received: " << reply << std::endl;
  50.     return a. exec();
  51. }

3.服务端

在Qt中新建控制台工程GRPC_Server,将上面的四个pb文件添加到工程中,main.cpp修改为如下所示


  
  1. #include <QCoreApplication>
  2. #include <iostream>
  3. #include <memory>
  4. #include <string>
  5. #include <grpcpp/ext/proto_server_reflection_plugin.h>
  6. #include <grpcpp/grpcpp.h>
  7. #include <grpcpp/health_check_service_interface.h>
  8. #include "helloworld.grpc.pb.h"
  9. using grpc::Server;
  10. using grpc::ServerBuilder;
  11. using grpc::ServerContext;
  12. using grpc::Status;
  13. using helloworld::Greeter;
  14. using helloworld::HelloReply;
  15. using helloworld::HelloRequest;
  16. // Logic and data behind the server's behavior.
  17. class GreeterServiceImpl final : public Greeter::Service {
  18.   Status SayHello(ServerContext* context, const HelloRequest* request,
  19.                   HelloReply* reply) override {
  20.     std::string prefix("Hello ");
  21.     reply-> set_greeting(prefix + request-> name());
  22.     return Status::OK;
  23.   }
  24. };
  25. void RunServer() {
  26.   std::string server_address("0.0.0.0:50051");
  27.   GreeterServiceImpl service;
  28.   grpc:: EnableDefaultHealthCheckService( true);
  29.   grpc::reflection:: InitProtoReflectionServerBuilderPlugin();
  30.   ServerBuilder builder;
  31.   // Listen on the given address without any authentication mechanism.
  32.   builder. AddListeningPort(server_address, grpc:: InsecureServerCredentials());
  33.   // Register "service" as the instance through which we'll communicate with
  34.   // clients. In this case it corresponds to an *synchronous* service.
  35.   builder. RegisterService(&service);
  36.   // Finally assemble the server.
  37.   std::unique_ptr<Server> server(builder.BuildAndStart());
  38.   std::cout << "Server listening on " << server_address << std::endl;
  39.   // Wait for the server to shutdown. Note that some other thread must be
  40.   // responsible for shutting down the server for this call to ever return.
  41.   server-> Wait();
  42. }
  43. int main(int argc, char *argv[])
  44. {
  45.     QCoreApplication a(argc, argv);
  46.     RunServer();
  47.     return a. exec();
  48. }

4.pro文件配置

GRPC_Client.pro和GRPC_Server.pro中都要添加如下内容


  
  1. GRPC_HOME="C:/Program Files (x86)/grpc"
  2. INCLUDEPATH += $$GRPC_HOME/include
  3. LIBS += -L$$GRPC_HOME/lib -lgrpc++ -lgrpc -lgpr -lgrpc_plugin_support -lgrpc_unsecure -lgrpc++_alts \
  4. -lgrpc++_error_details -lgrpc++_reflection -lgrpc++_unsecure -lgrpcpp_channelz -laddress_sorting \
  5. -lcares -labsl_bad_any_cast_impl -labsl_bad_optional_access -labsl_bad_variant_access -labsl_civil_time \
  6. -labsl_cordz_info -labsl_cord -labsl_cordz_functions -labsl_cordz_handle -labsl_cord_internal \
  7. -labsl_cordz_sample_token -labsl_exponential_biased -labsl_flags -labsl_flags_commandlineflag \
  8. -labsl_flags_commandlineflag_internal -labsl_flags_config -labsl_flags_internal -labsl_flags_marshalling \
  9. -labsl_flags_parse -labsl_flags_private_handle_accessor -labsl_flags_program_name -labsl_flags_reflection \
  10. -labsl_flags_usage -labsl_flags_usage_internal -labsl_synchronization -labsl_graphcycles_internal -labsl_hash \
  11. -labsl_city -labsl_hashtablez_sampler -labsl_log_severity -labsl_low_level_hash -labsl_periodic_sampler \
  12. -labsl_random_internal_pool_urbg -labsl_random_internal_seed_material -labsl_random_internal_randen_hwaes_impl \
  13. -labsl_random_distributions -labsl_random_internal_distribution_test_util -labsl_random_internal_platform \
  14. -labsl_random_internal_randen -labsl_random_internal_randen_hwaes -labsl_random_internal_randen_slow \
  15. -labsl_random_seed_gen_exception -labsl_random_seed_sequences -labsl_raw_hash_set -labsl_scoped_set_env \
  16. -labsl_spinlock_wait -labsl_status -labsl_statusor -labsl_str_format_internal -labsl_strerror -labsl_symbolize \
  17. -labsl_failure_signal_handler -labsl_examine_stack -labsl_stacktrace -labsl_leak_check \
  18. -labsl_debugging_internal -labsl_demangle_internal -labsl_strings -labsl_strings_internal -labsl_malloc_internal \
  19. -labsl_raw_logging_internal -labsl_throw_delegate -labsl_time -labsl_time_zone -labsl_int128 -labsl_base -lre2 \
  20. -lupb -lprotobuf -llibprotoc -lzlib.dll -lssl -lcrypto -ldbghelp
  21. LIBS += -lWS2_32 -lAdvapi32 -lbcrypt
  22. DEFINES += _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


转载:https://blog.csdn.net/caoshangpa/article/details/128402625
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场