文章
问答
冒泡
如何在C++中使用GRPC

之前java使用grpc的时候比较简单,直接引用jar包就行了,c++就会比较麻烦,还要自己编译部署。
1.生成grpc应用
1.1 从github  clone grpc的源码

git clone https://github.com/grpc/grpc.git


注意,如果自己checkout的版本编译有问题的话 还是用master吧,开始想指定v1.47.0 结果各种问题,还是老实用master的代码
1.2 拉取子模块依赖

git submodule update --init


https://github.com/grpc/grpc/blob/master/BUILDING.md
然后可以用cmake 进行部署了

1.3 直接用qt creator部署
这里,我们在源码都拉取完成之后,直接使用qt creator 来进行编译。由于我们是为了在后面QT中使用,QT6.x 要求C++17 ,所以,这里我们需要设置C++的版本
添加一段配置

set(CMAKE_CXX_STANDARD 17)

 

否则,默认是用C++14进行编译的

# Add c++14 flags
if (NOT DEFINED CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
else()
  if (CMAKE_CXX_STANDARD LESS 14)
    message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 14, please specify at least SET(CMAKE_CXX_STANDARD 14)")
  endif()

代码加载完成之后,可以看到里面有很多子项目

0

将部署的目录修改下,默认是在C:/Program Files(x86),这里,我们改成D:/tmp 下

0

构建这边加一个参数 install

0


运行部署,就会在目标文件,生成grpc的文件

0


通用的操作,部署release代码

0

2. 下面开始写grpc的测试代码
2.1 开始一个client端
创建一个client的工程,这里我们直接用debug生成的文件

include 文件夹下,将生成的头文件拷贝进来,将lib文件拷贝到lib文件夹下
将grpc部署生成的protoc.exe 和 grpc_cpp_plugin.exe 拷贝到protos文件夹下

这里我们以helloword为例,将helloword.proto文件copy到protos文件夹下,执行命令

./protoc.exe --cpp_out=./../protogen ./helloworld.proto
./protoc.exe --grpc_out=./../protogen --plugin=protoc-gen-grpc=./grpc_cpp_plugin.exe ./helloworld1.proto

 

在目标文件夹下生成了 
hellowrod.grpc.pb.cc  hellowrod.grpc.pb.h  hellowrod.pb.cc  hellowrod.pb.h 
到这里准备工作就做好了,下面开始进行代码

client 

#include <iostream>
#include <memory>
#include <string>

#include <grpcpp/grpcpp.h>
#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> 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.message();
        } else {
            std::cout << status.error_code() << ": " << status.error_message()
                      << std::endl;
            return "RPC failed";
        }
    }

private:
    std::unique_ptr<Greeter::Stub> stub_;
};


int main(int argc, char** argv) {
    std::string target_str;
    std::string arg_str("--target");
    if (argc > 1) {
        std::string arg_val = argv[1];
        size_t start_pos = arg_val.find(arg_str);
        if (start_pos != std::string::npos) {
            start_pos += arg_str.size();
            if (arg_val[start_pos] == '=') {
                target_str = arg_val.substr(start_pos + 1);
            } else {
                std::cout << "The only correct argument syntax is --target="
                          << std::endl;
                return 0;
            }
        } else {
            std::cout << "The only acceptable argument is --target=" << std::endl;
            return 0;
        }
    } else {
        target_str = "localhost:50051";
    }
    GreeterClient greeter(
            grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials()));
    std::string user("world");
    std::string reply = greeter.SayHello(user);
    std::cout << "Greeter received: " << reply << std::endl;
    std::cout << "Hello, World!" << std::endl;
    return 0;
}


代码很简单,就是把examples里的文件copy过来的,关键是下面的CMakeLists.txt 怎么写

cmake_minimum_required(VERSION 3.22)
project(grpc_client)

set(CMAKE_CXX_STANDARD 17)

#添加需要引入头文件的目录
include_directories("${PROJECT_SOURCE_DIR}/include/grpc" "${PROJECT_SOURCE_DIR}/protogen")
#添加需要链接的lib包目录
link_directories("${PROJECT_SOURCE_DIR}/lib")
#设置GRPC_LIBS 变量,这里就是把生成的lib全部列出
set(GRPC_LIBS
        absl_bad_any_cast_impl
        absl_bad_optional_access
        absl_bad_variant_access
        absl_base
        absl_city
        absl_civil_time
        absl_cord
        absl_cord_internal
        absl_cordz_functions
        absl_cordz_handle
        absl_cordz_info
        absl_cordz_sample_token
        absl_debugging_internal
        absl_demangle_internal
        absl_examine_stack
        absl_exponential_biased
        absl_failure_signal_handler
        absl_flags
        absl_flags_commandlineflag
        absl_flags_commandlineflag_internal
        absl_flags_config
        absl_flags_internal
        absl_flags_marshalling
        absl_flags_parse
        absl_flags_private_handle_accessor
        absl_flags_program_name
        absl_flags_reflection
        absl_flags_usage
        absl_flags_usage_internal
        absl_graphcycles_internal
        absl_hash
        absl_hashtablez_sampler
        absl_int128
        absl_leak_check
        absl_leak_check_disable
        absl_log_severity
        absl_low_level_hash
        absl_malloc_internal
        absl_periodic_sampler
        absl_random_distributions
        absl_random_internal_distribution_test_util
        absl_random_internal_platform
        absl_random_internal_pool_urbg
        absl_random_internal_randen
        absl_random_internal_randen_hwaes
        absl_random_internal_randen_hwaes_impl
        absl_random_internal_randen_slow
        absl_random_internal_seed_material
        absl_random_seed_gen_exception
        absl_random_seed_sequences
        absl_raw_hash_set
        absl_raw_logging_internal
        absl_scoped_set_env
        absl_spinlock_wait
        absl_stacktrace
        absl_status
        absl_statusor
        absl_str_format_internal
        absl_strerror
        absl_strings
        absl_strings_internal
        absl_symbolize
        absl_synchronization
        absl_throw_delegate
        absl_time
        absl_time_zone
        address_sorting
        cares
        crypto
        gpr
        grpc++
        grpc++_alts
        grpc++_error_details
        grpc++_reflection
        grpc++_unsecure
        grpc
        grpc_plugin_support
        grpc_unsecure
        grpcpp_channelz
        libprotobuf-lited
        libprotobufd
        libprotocd
        re2
        ssl
        upb
        zlibd
        zlibstaticd
        )

#将propto生成的文件一起打到 protogen这个lib里
add_library(proptogen ${PROJECT_SOURCE_DIR}/protogen/helloworld.grpc.pb.cc
        ${PROJECT_SOURCE_DIR}/protogen/helloworld.grpc.pb.h
        ${PROJECT_SOURCE_DIR}/protogen/helloworld.pb.cc
        ${PROJECT_SOURCE_DIR}/protogen/helloworld.pb.h)

add_executable(grpc_client main.cpp)
#链接lib 这里要加一个ws2_32 否则出现异常
target_link_libraries(grpc_client proptogen ${GRPC_LIBS} ws2_32)

不添加ws2_32 就会出现下面的异常 

cares.lib(ares_process.c.obj) : error LNK2019: 无法解析的外部符号 __imp_ioctlsocket,函数 setsocknonblock 中引用了该符号
cares.lib(ares_process.c.obj) : error LNK2019: 无法解析的外部符号 __imp_recv,函数 socket_recv 中引用了该符号
cares.lib(ares_process.c.obj) : error LNK2019: 无法解析的外部符号 __imp_recvfrom,函数 socket_recvfrom 中引用了该符号
cares.lib(ares_process.c.obj) : error LNK2019: 无法解析的外部符号 __imp_send,函数 socket_write 中引用了该符号
cares.lib(ares_writev.c.obj) : error LNK2001: 无法解析的外部符号 __imp_send
cares.lib(ares_getnameinfo.c.obj) : error LNK2019: 无法解析的外部符号 __imp_getservbyport,函数 lookup_service 中引用了该符号
cares.lib(ares_getaddrinfo.c.obj) : error LNK2019: 无法解析的外部符号 __imp_getservbyname,函数 lookup_service 中引用了该符号
grpc_client.exe : fatal error LNK1120: 35 个无法解析的外部命令


2.2 server端如法炮制

#include <iostream>

#include <grpcpp/grpcpp.h>
#include "helloworld.grpc.pb.h"

using namespace grpc;
using namespace helloworld;

class GreeterServiceImpl final : public Greeter::Service {
    Status SayHello(ServerContext* context, const HelloRequest* request,
                    HelloReply* reply) override {
        std::string prefix("Hello ");
        reply->set_message(prefix + request->name());
        return Status::OK;
    }
};

void RunServer() {
    std::string server_address("0.0.0.0:50051");
    GreeterServiceImpl service;

    grpc::EnableDefaultHealthCheckService(true);

    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() {
    RunServer();
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.22)
project(grpc_server)

set(CMAKE_CXX_STANDARD 17)

include_directories("${PROJECT_SOURCE_DIR}/include/grpc" "${PROJECT_SOURCE_DIR}/protogen")
link_directories("${PROJECT_SOURCE_DIR}/lib")

set(GRPC_LIBS
        absl_bad_any_cast_impl
        absl_bad_optional_access
        absl_bad_variant_access
        absl_base
        absl_city
        absl_civil_time
        absl_cord
        absl_cord_internal
        absl_cordz_functions
        absl_cordz_handle
        absl_cordz_info
        absl_cordz_sample_token
        absl_debugging_internal
        absl_demangle_internal
        absl_examine_stack
        absl_exponential_biased
        absl_failure_signal_handler
        absl_flags
        absl_flags_commandlineflag
        absl_flags_commandlineflag_internal
        absl_flags_config
        absl_flags_internal
        absl_flags_marshalling
        absl_flags_parse
        absl_flags_private_handle_accessor
        absl_flags_program_name
        absl_flags_reflection
        absl_flags_usage
        absl_flags_usage_internal
        absl_graphcycles_internal
        absl_hash
        absl_hashtablez_sampler
        absl_int128
        absl_leak_check
        absl_leak_check_disable
        absl_log_severity
        absl_low_level_hash
        absl_malloc_internal
        absl_periodic_sampler
        absl_random_distributions
        absl_random_internal_distribution_test_util
        absl_random_internal_platform
        absl_random_internal_pool_urbg
        absl_random_internal_randen
        absl_random_internal_randen_hwaes
        absl_random_internal_randen_hwaes_impl
        absl_random_internal_randen_slow
        absl_random_internal_seed_material
        absl_random_seed_gen_exception
        absl_random_seed_sequences
        absl_raw_hash_set
        absl_raw_logging_internal
        absl_scoped_set_env
        absl_spinlock_wait
        absl_stacktrace
        absl_status
        absl_statusor
        absl_str_format_internal
        absl_strerror
        absl_strings
        absl_strings_internal
        absl_symbolize
        absl_synchronization
        absl_throw_delegate
        absl_time
        absl_time_zone
        address_sorting
        address_sorting
        cares
        crypto
        gpr
        grpc++
        grpc++_alts
        grpc++_error_details
        grpc++_reflection
        grpc++_unsecure
        grpc
        grpc_plugin_support
        grpc_unsecure
        grpcpp_channelz
        libprotobuf-lited
        libprotobufd
        libprotocd
        re2
        ssl
        upb
        zlibd
        zlibstaticd
        )

add_library(protogen ${PROJECT_SOURCE_DIR}/protogen/helloworld.grpc.pb.cc
        ${PROJECT_SOURCE_DIR}/protogen/helloworld.grpc.pb.h
        ${PROJECT_SOURCE_DIR}/protogen/helloworld.pb.cc
        ${PROJECT_SOURCE_DIR}/protogen/helloworld.pb.h)

add_executable(grpc_server main.cpp )

target_link_libraries(grpc_server protogen ${GRPC_LIBS})

server启动

0


 client 启动

0

达到预期
之前的grpc生成的文件,最好自己保存下来,搞一次挺费事的,特别的咱们这个网络环境

c++
gRPC

关于作者

落雁沙
非典型码农
获得点赞
文章被阅读