開始使用gRPC之前,需要先準備好gRPC,可參考博主另一篇博文 Win10下編譯gRPC 。
本文主要記錄使用gRPC做一個簡單的HelloWorld實例的過程以及其中遇到的一些問題;
HelloWorld實例的代碼很簡單,借用了網上的例子代碼,博主只做了很小的改動。
下面開始實戰過程。
1,新建三個VC項目,如下圖,其中GrpcServer, GrpcClient 爲控制檯(console)程序, GrpcLibrary爲靜態庫
2,編寫proto並編譯,在GrpcLibrary項目添加文件HelloWorld.proto,編寫如下內容
syntax = "proto3"; package GrpcLibrary; service GrpcService{ rpc SayHello(HelloRequest) returns (HelloReply) {} } message HelloRequest{ string name = 1; } message HelloReply{ string message = 1; }
把相關grpc和protobuf的exe文件以及helloworld.proto放到同一個文件夾,則可以使用以下指令編譯proto。
博主的做法是把protoc.exe和相關DLL文件拷貝到grpc的可執行程序文件夾下(例如....\gRPC\mybuild64\Debug)。
protoc.exe --cpp_out GrpcLibrary HelloWorld.proto --grpc_out GrpcLibrary --plugin=protoc-gen-grpc=grpc_cpp_plugin.exe
編譯成功,生成HelloWorld.pb.h,HelloWorld.pb.cc,HelloWorld.grpc.pb.h,HelloWorld.grpc.pb.cc四個文件,
將這四個文件複製到grpcLibrary項目的文件夾,並加入VC項目中。
最後GrpcClient、GrpcServer分別引用類庫GrpcLibrary。
3,編寫server和client的代碼,分別如下:
// GrpcServer.cpp #include <iostream> #include <memory> #include <string> #include <grpcpp/grpcpp.h> #ifdef BAZEL_BUILD #include "examples/protos/helloworld.grpc.pb.h" #else #include "HelloWorld.grpc.pb.h" #endif using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; using GrpcLibrary::HelloRequest; using GrpcLibrary::HelloReply; using GrpcLibrary::GrpcService; // Logic and data behind the server's behavior. class GreeterServiceImpl final : public GrpcService::Service { Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override { std::string prefix("A Hello World demo, echo client request name: "); reply->set_message(prefix + request->name()); return Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; 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> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; // Wait for the server to shutdown. Note that some other thread must be // responsible for shutting down the server for this call to ever return. server->Wait(); } int main(int argc, char** argv) { RunServer(); return 0; }
// GrpcClient.cpp #include <iostream> #include <memory> #include <string> #include <grpcpp/grpcpp.h> #ifdef BAZEL_BUILD #include "examples/protos/helloworld.grpc.pb.h" #else #include "helloworld.grpc.pb.h" #endif using grpc::Channel; using grpc::ClientContext; using grpc::Status; using GrpcLibrary::HelloRequest; using GrpcLibrary::HelloReply; using GrpcLibrary::GrpcService; class GreeterClient { public: GreeterClient(std::shared_ptr<Channel> channel) : stub_(GrpcService::NewStub(channel)) {} 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.message(); } else { std::cout << status.error_code() << ": " << status.error_message() << std::endl; return "RPC failed"; } } private: std::unique_ptr<GrpcService::Stub> stub_; }; int main(int argc, char** 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; system("pause"); return 0; }
4,配置項目所需的輸入庫(gRPC以及相關的第三方依賴庫)
以grpcServer爲例,grpcClient的相關配置項與grpcServer相同。
C++附加目錄:
D:\MyDemoProj\GrpcDemo\GrpcLibrary;E:\DevTools\gRPC\include;E:\DevTools\gRPC\third_party\protobuf\src;E:\DevTools\gRPC\third_party\abseil-cpp;
鏈接庫附加目錄:
D:\MyDemoProj\GrpcDemo\x64\Debug;
E:\DevTools\gRPC\mybuild64\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\base\Debug;
E:\DevTools\gRPC\mybuild64\third_party\boringssl-with-bazel\Debug;
E:\DevTools\gRPC\mybuild64\third_party\re2\Debug;
E:\DevTools\gRPC\mybuild64\third_party\zlib\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\synchronization\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\types\Debug
;E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\time\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\strings\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\status\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\random\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\hash\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\numeric\Debug;
E:\DevTools\gRPC\mybuild64\third_party\cares\cares\lib\Debug;
E:\DevTools\gRPC\mybuild64\third_party\abseil-cpp\absl\debugging\Debug;
附加鏈接庫有這麼多(可能有部分不需要,沒有逐個覈對):
grpc_unsecure.lib;grpc++.lib;grpc++_alts.lib;grpc++_error_details.lib;grpc++_reflection.lib;
grpc++_unsecure.lib;grpcpp_channelz.lib;libprotobufd.lib;upb.lib;re2.lib;ssl.lib;crypto.lib;GrpcLibrary.lib;
absl_debugging_internal.lib;absl_demangle_internal.lib;absl_examine_stack.lib;absl_failure_signal_handler.lib;
absl_leak_check.lib;absl_leak_check_disable.lib;absl_stacktrace.lib;absl_symbolize.lib;cares.lib;absl_int128.lib;
absl_city.lib;absl_hash.lib;absl_low_level_hash.lib;absl_random_distributions.lib;absl_random_internal_distribution_test_util.lib;
absl_random_internal_platform.lib;absl_random_internal_pool_urbg.lib;absl_random_internal_randen.lib;
absl_random_internal_randen_hwaes.lib;absl_random_internal_randen_hwaes_impl.lib;absl_random_internal_randen_slow.lib;
absl_random_internal_seed_material.lib;absl_random_seed_gen_exception.lib;absl_random_seed_sequences.lib;absl_status.lib;
absl_statusor.lib;absl_bad_any_cast_impl.lib;absl_bad_optional_access.lib;absl_bad_variant_access.lib;
absl_graphcycles_internal.lib;absl_synchronization.lib;absl_civil_time.lib;absl_time.lib;absl_time_zone.lib;absl_cord.lib;
absl_cord_internal.lib;absl_cordz_functions.lib;absl_cordz_handle.lib;absl_cordz_info.lib;absl_cordz_sample_token.lib;
absl_str_format_internal.lib;absl_strings.lib;absl_strings_internal.lib;absl_base.lib;absl_log_severity.lib;
absl_malloc_internal.lib;absl_raw_logging_internal.lib;absl_scoped_set_env.lib;absl_spinlock_wait.lib;
absl_strerror.lib;absl_throw_delegate.lib;zlibd.lib;gpr.lib;address_sorting.lib;grpc.lib;grpc_plugin_support.lib;
5.編譯VC項目,成功後先執行GrpcServer.exe, 再執行GrpcClient.exe, 簡單的helloworld就完成了。