VC++中使用gRPC的編寫helloworld的詳細過程與經驗

開始使用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就完成了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章