VS2019创建cMake工程实现gRPC客户服务端调用

目录

1. 新建cmake工程

2. 编写proto文件

3 准备环境

4. 将第三方依赖文件放到depends中

5. 编写CMakeLists.txt 生成*.pb.h , *.pb.c, *.grpc.pb.cc;*grpc.pb.h文件

6. 在gRPC_Server中实现proto文件定义的接口方法

7. 新建gRPC_Client文件夹,并编写Client代码,完成gRPC接口测试

8. 测试gRPC接口


1. 新建cmake工程

子项目名称为gRPC_Server,后面用做为gRPC服务,创建成功之后,VS2019将自动的帮我们新建一个gRPC_Server.h和gRPC_Server.cpp文件以及一个CMakeLists.txt脚本文件。

为了后面好管理,我们再新建cmake,gRPC_Client,depends和proto四个文件夹,其中cmake文件夹:保存一些自定义的或者第三方的cmake文件;gRPC_Client:保存gRPC客户端程序,用于测试gRPC_Server中gRPC服务接口;depends:保存第三方的依赖库、头文件和源文件等;proto:存放自定义的proto文件。

 

2. 编写proto文件

定义一个calculator服务,就一个接口Add方法

3 准备环境

在windows或者Linux(Ubuntu/CentOS/RetHat等)安装cMake,具体过程请参考百度,这里就不展开了。

安装好cmake后,如果你的是window系统,双击CMake应用程序,将出现下面的对话框,这个工具的目的主要是,对刚刚新建的cMake工程进行配置并生成平台相关的工程,如在windows中会生成MSVC工程,Unix中生成Makefile工程,从而实现一套代码可在不同平台上运行的目的。

4. 将第三方依赖文件放到depends中

本篇要演示的是gRPC接口的调用过程,因此依赖gRPC和protobuf两个第三方库,这里我们从官网下载相关的头文件和源文件以及release版本的库文件并将这些文件放入到depends文件夹中。

5. 编写CMakeLists.txt 生成*.pb.h , *.pb.c, *.grpc.pb.cc;*grpc.pb.h文件

首先,在根节点中的CMakeLists.txt添加子目录并设置编译器、工程名称等

接着,修改gRPC_Server中的CMakeLists.txt内容,这里我们需要做如下工作:

1)在depends文件夹中添加gRPC和protobuf的依赖库、源文件和头文件;

2)编写自定义的cmake文件:findgrpc.cmake和findprotobuf.cmake,这两个文件负责链接depends中gRPC和protobuf的依赖库、源文件和头文件;

3)修改gRPC_Server中的CMakeLists.txt,生成*.pb.h , *.pb.c, *.grpc.pb.cc;*grpc.pb.h接口文件

4)添加连接库和源文件以及头文件,生成gRPC_Server.exe

findgrpc.cmake脚本如下:

# Find required gRPC package

if(NOT MSVC)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else()
  add_definitions(-D_WIN32_WINNT=0x600)
endif()

if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
	set(PLATFORM windows)
else()
	if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
		set(PLATFORM aarch64)
    else()
        set(PLATFORM linux)
    endif()
endif()

find_package(Threads REQUIRED)

list(APPEND CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/depends/gRPC/${PLATFORM}/cmake)
message(STATUS  ${CMAKE_SOURCE_DIR}/depends/gRPC/${PLATFORM}/cmake)
set(Protobuf_DIR ${CMAKE_SOURCE_DIR}/depends/gRPC/${PLATFORM}/cmake)
set(gRPC_DIR ${CMAKE_SOURCE_DIR}/depends/gRPC/${PLATFORM}/lib/cmake/grpc)
set(gRPC_BIN_DIR ${CMAKE_SOURCE_DIR}/depends/gRPC/${PLATFORM}/bin)

set(protobuf_MODULE_COMPATIBLE TRUE)
find_package(Protobuf CONFIG REQUIRED)

if(PROTOBUF_FOUND)
	message(STATUS "Using Protobuf v${Protobuf_VERSION}")
else()
    message("protobuf library is needed but can't be found")
endif()

find_package(gRPC CONFIG REQUIRED)
message(STATUS "Using grpc v${gRPC_VERSION}")

set(PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
set(GRPC_GRPCPP gRPC::grpc++)
set(GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
set(REFLECTION gRPC::grpc++_reflection)
set(PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)

findprotobuf.cmake如下

# 判断系统类型
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
	set(PROTOBUF_DIR_TOTAL ${CMAKE_SOURCE_DIR}/depends/Protobuf)
	set(Protobuf_INCLUDE_DIR ${PROTOBUF_DIR_TOTAL}/include)
	message("-------find protobuf, windows mode path: ${PROTOBUF_DIR_TOTAL}-----")
	set(Protobuf_LIBRARY ${PROTOBUF_DIR_TOTAL}/lib/windows)
	set(Protobuf_PROTOC_EXECUTABLE ${PROTOBUF_DIR_TOTAL}/bin/windows/protoc.exe)
	set(PROTOBUF_LIB libprotobuf.lib)
	set(PROTOC_LIB libprotoc.lib)
else()
	if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
		set(AARCH64_PATH ${PROJECT_SOURCE_DIR}/depends/Protobuf)
        set(Protobuf_INCLUDE_DIR ${AARCH64_PATH}/include)
        set(Protobuf_LIBRARY ${AARCH64_PATH}/lib/aarch64)
        set(Protobuf_PROTOC_EXECUTABLE ${AARCH64_PATH}/bin/aarch64/protoc)
    else()
        set(AARCH64_PATH ${PROJECT_SOURCE_DIR}/depends/Protobuf)
        set(Protobuf_INCLUDE_DIR ${AARCH64_PATH}/include)
        set(Protobuf_LIBRARY ${AARCH64_PATH}/lib/linux)
        set(Protobuf_PROTOC_EXECUTABLE ${AARCH64_PATH}/bin/linux/protoc)
    endif()
endif()
	set(PROTOBUF_LIB protobuf)
	set(PROTOC_LIB protoc)

# 加载依赖包
find_package(Protobuf REQUIRED)
if(PROTOBUF_FOUND)
    message(STATUS "Protobuf FOUND!" ${PROTOBUF_INCLUDE_DIRS})
    include_directories(${PROTOBUF_INCLUDE_DIRS})
    link_directories(${Protobuf_LIBRARY})
else()
    message(FATAL_ERROR "protobuf library is needed but can't be found")
endif()

gRPC_Server中的CMakeLists.txt

cmake_minimum_required (VERSION 3.8)

# 设置工程名称
project ("gRPC_Server")
set(CMAKE_PROJECT_NAME gRPC_Server)

# 包含gRPC和protobuf头文件和proto接口文件
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/findgrpc.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/findprotobuf.cmake")

# 加载依赖包
find_package(protobuf CONFIG REQUIRED)
find_package(gRPC CONFIG REQUIRED)
find_package(Threads)

# 获取文件和路径
set(grpc_proto_file_name calculator)
get_filename_component(grpc_proto "${CMAKE_CURRENT_SOURCE_DIR}/../proto/${grpc_proto_file_name}.proto" ABSOLUTE)
get_filename_component(grpc_proto_path "${grpc_proto}" PATH)


# Cmake find modules
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")

# 获取文件和路径
set(grpc_proto_file_name calculator)
set(grpc_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/${grpc_proto_file_name}.pb.cc")
set(grpc_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/${grpc_proto_file_name}.pb.h")
set(grpc_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/${grpc_proto_file_name}.grpc.pb.cc")
set(grpc_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/${grpc_proto_file_name}.grpc.pb.h")

# 生成 *.ph.cc.h 文件 by protoc.exe
add_custom_command(
	OUTPUT 	"${grpc_proto_srcs}" 
			"${grpc_proto_hdrs}"
			"${grpc_grpc_srcs}"
			"${grpc_grpc_hdrs}"
	COMMAND ${PROTOBUF_PROTOC}
	ARGS 	--grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
			--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
			-I "${grpc_proto_path}"
			--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN_EXECUTABLE}"
			"${grpc_proto}"
	DEPENDS "${grpc_proto}"
)

# 添加头文件
set(GRPCSERVER_HDRS_DIR
	${CMAKE_CURRENT_BINARY_DIR}
	${grpc_grpc_hdrs}
	${grpc_proto_hdrs}
	${PROTO_HDRS}
	${DEFAULT_INCLUDE_DIRECTORIES}
	"gRPC_Server.h"
)
# 通过这行,后面在编译时,将自动的把这些头文件连接到我们的工程中,注意,这里新手容易入坑!
include_directories(${GRPCSERVER_HDRS_DIR})

# 添加源文件
set(GRPCSERVER_SRC_FILES 
	${grpc_proto_srcs}
	${grpc_grpc_srcs}
	${PROTO_SRCS}	
	"gRPC_Server.cpp"
)

# 关闭优化
SET_SOURCE_FILES_PROPERTIES(${GRPCSERVER_SRC_FILES} PROPERTIES COMPILE_FLAGS -Od)

# 添加编译源文件
add_executable(${PROJECT_NAME} ${GRPCSERVER_SRC_FILES})

# 添加目标连接库
target_link_libraries(${PROJECT_NAME}
	${REFLECTION}
	${GRPC_GRPCPP}
	${PROTOBUF_LIBPROTOBUF}
	${DEFAULT_LIBRARIES}
)

单击Rebuild生成gRPC_Server.exe和gRPC和Protobuf的接口文件

6. 在gRPC_Server中实现proto文件定义的接口方法

首先,我们需要在gRPC_Server中引用刚刚生成的接口文件calculator.grpc.pb.h和grpc++/grpc++.h

接着,实现接口方法,具体如下图所示:


#include "gRPC_Server.h"
#include "calculator.grpc.pb.h"
#include "grpc++/grpc++.h"

using namespace std;

class CalcualtorService : public calc::Caltulator::Service
{
public:
	virtual ::grpc::Status Add(::grpc::ServerContext* context, const ::calc::InParams* request, ::calc::OutParams* response) override
	{
		response->set_sum(request->a() + request->b());
		return grpc::Status::OK;
	}
};


int main()
{
	std::string server_address("0.0.0.0:5152");
	CalcualtorService calcSrv;
	grpc::ServerBuilder builder;
	builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
	builder.RegisterService(&calcSrv);
	std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
	std::cout << "Server listening on " << server_address << std::endl;
	server->Wait();
	return 0;
}

最后,我们再重新编译

7. 新建gRPC_Client文件夹,并编写Client代码,完成gRPC接口测试

在客户端中添加main.cpp,测试代码如下:

#include <iostream>
#include<cstdio>
#include <memory>
#include "calculator.grpc.pb.h"
#include "grpc++/grpc++.h"

class Client
{
public:
	Client(std::shared_ptr<grpc::Channel> channel) : stub_(calc::Caltulator::NewStub(channel))
	{}

	google::protobuf::int32 Add(google::protobuf::int32 a, google::protobuf::int32 b)
	{
		calc::InParams request;
		request.set_a(a);
		request.set_b(b);
		calc::OutParams response;
		grpc::ClientContext context;
		grpc::Status status = stub_->Add(&context, request, &response);
		if (status.ok())
		{
			return response.sum();
		}
		else
		{
			return -1;
		}
	}
private:
	std::unique_ptr<calc::Caltulator::Stub> stub_;
};


int main()
{
	std::cout << "=====================Test Add==================" << std::endl;
	Client client(grpc::CreateChannel("localhost:5152", grpc::InsecureChannelCredentials()));
	auto result = client.Add(1, 260);
	std::cout << "1 + 260 = " << result << std::endl;
    getchar();
	return 0;
}

编写CMakeLists.txt脚本文件

cmake_minimum_required (VERSION 3.8)

# 设置工程名称并选择编译语言c++
project(gRPC_Client C CXX)

# 设置工程名称
set(CMAKE_PROJECT_NAME ${PROJECT_NAME})

# 检查平台
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
	set(PLATFORM windows)
else()
	if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
		set(PLATFORM aarch64)
    else()
        set(PLATFORM linux)
    endif()
endif()

# 包含头文件
set(CMAKE_GRPC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/depends/gRPC/${PLATFORM}/include")
# calculator.pb.cc文件在gRPC_Server文件夹中,需要注意下路径,这里也是新手容易掉坑的地方
set(CMAKE_CURRENT_BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/../gRPC_Server")
include_directories(${CMAKE_CURRENT_BIN_DIR} ${CMAKE_GRPC_DIR})
message(STATUS "[CMAKE_CURRENT_BIN_DIR]->" ${CMAKE_CURRENT_BIN_DIR})

# 包含第三方脚本
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/findgrpc.cmake")

# 获取文件和路径
set(grpc_proto_file_name calculator)
set(grpc_proto_srcs "${CMAKE_CURRENT_BIN_DIR}/${grpc_proto_file_name}.pb.cc")
set(grpc_proto_hdrs "${CMAKE_CURRENT_BIN_DIR}/${grpc_proto_file_name}.pb.h")
set(grpc_grpc_srcs "${CMAKE_CURRENT_BIN_DIR}/${grpc_proto_file_name}.grpc.pb.cc")
set(grpc_grpc_hdrs "${CMAKE_CURRENT_BIN_DIR}/${grpc_proto_file_name}.grpc.pb.h")

# 包含编译的源文件
aux_source_directory(. DIR_SRCS)
set(CMAKECLIENT_SRC_FILES 
	${grpc_proto_srcs}
	${grpc_grpc_srcs}
	${PROTO_SRCS}	
	${DIR_SRCS}
)

# 包含头文件
set(CMAKECLIENT_HDRS_DIR
	${CMAKE_CURRENT_BINARY_DIR}
	${grpc_grpc_hdrs}
	${grpc_proto_hdrs}
	${PROTO_HDRS}
	${DEFAULT_INCLUDE_DIRECTORIES}
)
include_directories(${CMAKECLIENT_HDRS_DIR})
message(STATUS "[CMAKECLIENT_SRC_FILES]->"${PROJECT_NAME} ${CMAKECLIENT_SRC_FILES})
add_executable(${PROJECT_NAME} ${CMAKECLIENT_SRC_FILES})

# 添加目标连接库
target_link_libraries(${PROJECT_NAME}
	${REFLECTION}
	${GRPC_GRPCPP}
	${PROTOBUF_LIBPROTOBUF}
	${DEFAULT_LIBRARIES}
)

最后在根节点中添加刚刚新建的子目录

# 最低版本
cmake_minimum_required (VERSION 3.8)

# 工程名称
project ("CMake_GRPC")

# 设置release模式
set(CMAKE_BUILD_TYPE "Release")

# 选择编译语言c++
project(CMakeServer C CXX)

# 设置编译器
if(NOT MSVC)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else()
  add_definitions(-D_WIN32_WINNT=0x600)
endif()

# 添加子工程
add_subdirectory ("gRPC_Server")
# 添加客户端子工程
add_subdirectory ("gRPC_Client")

重新编译

8. 测试gRPC接口

先打开服务端程序;接着打开客户端程序,测试结果如下:

参考文献:

[1] https://blog.csdn.net/vc66vcc/article/details/80597027

[2] https://blog.csdn.net/weixin_28927079/article/details/97262243

总结:

        以上是VS2019创建cMake工程并实现gRPC客户服务端程序的基本过程,希望通过简单的例子让大家对CMake、gRPC和protobuf有个基本的认识。为大家跨平台编程方面提供一点小小的参考。今天先写到这里,后面会将代码链接地址一同附上,希望对大家工作有助,谢谢!

 

代码链接地址:https://download.csdn.net/download/pathfinder1987/19733881?spm=1001.2014.3001.5501

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值