之前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()
代码加载完成之后,可以看到里面有很多子项目
将部署的目录修改下,默认是在C:/Program Files(x86),这里,我们改成D:/tmp 下
构建这边加一个参数 install
运行部署,就会在目标文件,生成grpc的文件
通用的操作,部署release代码
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启动
client 启动
达到预期
之前的grpc生成的文件,最好自己保存下来,搞一次挺费事的,特别的咱们这个网络环境