grpc代码部分


模块根目录下CMakeLists.txt

add_subdirectory(server)
add_subdirectory(client)

用于将子目录中的 CMakeLists.txt 文件添加到主构建系统中。这些子目录通常包含独立模块或组件(例如服务器和客户端的代码),并且各自有自己的构建逻辑。
1、这行命令将 server 目录下的 CMakeLists.txt 文件包含到当前的 CMake 构建系统中。CMake 会递归地处理 server 目录中的构建逻辑,编译和链接该目录下的代码。server 目录通常包含服务器端代码,比如服务的实现、依赖库等。
2、这行命令将 client 目录下的 CMakeLists.txt 文件包含到当前的 CMake 构建系统中。同样地,CMake 会处理 client 目录中的构建逻辑,编译和链接该目录下的代码。client 目录通常包含客户端代码,比如 gRPC 客户端的实现、调用服务的逻辑等。
作用
模块化构建:add_subdirectory 命令允许你将项目划分为多个模块(如 server 和 client),每个模块可以有自己独立的构建逻辑。这使得项目结构更加清晰,也便于团队分工协作。
递归处理:CMake 会递归地处理子目录中的 CMakeLists.txt 文件。这意味着在子目录中的配置会自动与顶层的配置集成。
独立开发:使用 add_subdirectory 后,你可以独立地开发和测试 server 和 client 模块,而不必依赖整个项目的构建。

server下

CMakeLists.txt

#
# Dependencies
#
# find_package(Threads)这行代码用于找到并配置线程库,确保项目可以使用线程功能。在使用 gRPC 时,线程库通常是必需的。

#
# Sources
# CMakeLists.txt 文件片段定义了一个简单的 CMake 构建配置,用于构建一个 gRPC 服务器项目
set(SOURCES
    main.cpp
    rpc_manager.cpp # 定义了一个名为 SOURCES 的变量,其中包含了项目的源文件列表
)

# source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})

# target_include_directories(server PUBLIC
#   ${PROJECT_SOURCE_DIR}/..
# )
#
# Target
#
add_executable(server ${SOURCES})# 创建了一个名为 server 的可执行文件,使用 SOURCES 变量中定义的源文件进行构建。
target_link_libraries(server # 这段代码将 monitor_proto 库链接到可执行文件 server。monitor_proto 可能是由 protobuf 和 gRPC 编译器生成的库,包含了 RPC 服务和消息的定义。
    PUBLIC
    monitor_proto
)
  1. find_package(Threads):用于查找并配置系统中的线程库(如 pthread),确保项目可以使用多线程功能。在使用 gRPC 时,线程库通常是必需的,因为 gRPC 服务器通常是多线程的,以便处理多个并发的客户端请求。
  2. set(SOURCES …) 定义了一个名为 SOURCES 的变量,该变量包含了项目的源文件列表。
  3. target_include_directories 可以告诉编译器在哪里寻找头文件。
  4. ${PROJECT_SOURCE_DIR}/… 是上一级目录的路径。这通常用于引用一些共享的头文件或依赖项。
  5. add_executable(server ${SOURCES}) 创建了一个名为 server 的可执行文件,使用 SOURCES 变量中定义的源文件进行构建。
  6. target_link_libraries(server PUBLIC monitor_proto) 将名为 monitor_proto 的库链接到 server 可执行文件。monitor_proto 很可能是由 Protocol Buffers 和 gRPC 编译器生成的库,包含了 RPC 服务的实现和消息定义。
    这段 CMakeLists.txt 文件主要用于配置一个简单的 gRPC 服务器项目,它通过 find_package 查找必要的线程库,定义源文件,并生成一个可执行的服务器程序。它还链接了 gRPC 相关的 monitor_proto 库,确保服务器能够处理 gRPC 请求。
    线程库 确保多线程支持,必需的库被正确配置。
    源文件列表 定义了哪些源文件会被编译为可执行文件。
    目标包含目录(虽然被注释)为编译器指定了头文件搜索路径。
    生成可执行文件 实现了 gRPC 服务器的编译。
    链接库 将生成的 gRPC 服务和消息实现链接到服务器可执行文件中。

main.cpp


#include <iostream>
#include <grpc/grpc.h>
#include <grpcpp/server_builder.h>
#include "rpc_manager.h"

constexpr char kServerPortInfo[] = "0.0.0.0:50051";//定义了服务器监听的地址和端口。0.0.0.0:50051 表示服务器在端口 50051 上监听所有的 IP 地址。
void InitServer() {
  grpc::ServerBuilder builder;//创建一个服务器构建器对象。
  builder.AddListeningPort(kServerPortInfo, grpc::InsecureServerCredentials());//添加服务器监听的地址和端口,并使用不需要安全认证的凭证。

  monitor::GrpcManagerImpl grpc_server;//创建一个 GrpcManagerImpl 服务实例。
  builder.RegisterService(&grpc_server);//将服务实例注册到服务器构建器。

  std::unique_ptr<grpc::Server> server(builder.BuildAndStart());//构建并启动服务器。
  server->Wait();//使服务器在等待客户端请求时保持运行状态。

  return;
}

int main() {
  InitServer();//调用 InitServer 函数来初始化并启动 gRPC 服务器。
  return 0;
}

这段代码展示了如何使用 gRPC 库创建和启动一个简单的 gRPC 服务器。
1、包含必要的头文件

#include <grpc/grpc.h>:包含 gRPC 的核心库。
#include <grpcpp/server_builder.h>:包含 gRPC 服务器构建器相关的库。
#include "rpc_manager.h":这是用户定义的头文件,可能包含 GrpcManagerImpl 类的定义,该类实现了具体的 gRPC 服务。

2、定义服务器的监听地址和端口

constexpr char kServerPortInfo[] = "0.0.0.0:50051";

定义了服务器监听的地址和端口,0.0.0.0:50051 表示服务器会在所有可用的网络接口上监听端口 50051。
3、初始化并启动服务器

void InitServer() {
  grpc::ServerBuilder builder;

创建一个 grpc::ServerBuilder 对象,用于配置和构建 gRPC 服务器。

  builder.AddListeningPort(kServerPortInfo, grpc::InsecureServerCredentials());

调用 AddListeningPort 方法,指定服务器监听的地址和端口,以及使用的凭证类型。这里使用的是 InsecureServerCredentials(),表示不使用 SSL/TLS 进行安全通信(即不进行加密认证)。

  monitor::GrpcManagerImpl grpc_server;
  builder.RegisterService(&grpc_server);

创建一个 GrpcManagerImpl 服务实例,这个类是用户在 rpc_manager.h 中定义的 gRPC 服务实现。RegisterService 方法将这个服务实例注册到服务器中。

  std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
  server->Wait();

使用 BuildAndStart() 构建并启动服务器,返回一std::unique_ptrgrpc::Server 对象,表示服务器实例。调用 server->Wait(),使服务器在等待客户端请求时保持运行状态。

rpc_manager.cpp

这段代码展示了一个 gRPC 服务端的实现,GrpcManagerImpl 类提供了两个方法:SetMonitorInfo 和 GetMonitorInfo。这些方法用于接收和返回监控信息。

#include "rpc_manager.h"
#include <iostream>
//代码实现了 gRPC 服务端的 GrpcManagerImpl 类,提供了 SetMonitorInfo 和 GetMonitorInfo 方法
namespace monitor {
GrpcManagerImpl::GrpcManagerImpl() {}

GrpcManagerImpl::~GrpcManagerImpl() {}
::grpc::Status GrpcManagerImpl::SetMonitorInfo(//此方法接收一个监控信息请求,并将其存储在 monitor_infos_ 成员变量中。
    ::grpc::ServerContext* context,
    const ::monitor::proto::MonitorInfo* request,
    ::google::protobuf::Empty* response) {
  monitor_infos_.Clear();//清除之前存储的信息。
  monitor_infos_ = *request;//将新的监控信息存储在 monitor_infos_ 中。
  std::cout << "jinru" << request->soft_irq_size() << std::endl;//输出调试信息。
  //   for (int i = 0; i < request->soft_irq_size(); i++) {
  //     std::cout << request->soft_irq(i).cpu() << " " <<
  //     request->soft_irq(i).hi()
  //               << " " << request->soft_irq(i).timer() << " "
  //               << request->soft_irq(i).net_tx() << " "
  //               << request->soft_irq(i).net_rx() << " "
  //               << request->soft_irq(i).block() << " "
  //               << request->soft_irq(i).irq_poll() << std::endl;
  //   }
  return grpc::Status::OK;
}
::grpc::Status GrpcManagerImpl::GetMonitorInfo(//此方法返回之前存储的监控信息。
    ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
    ::monitor::proto::MonitorInfo* response) {
  //   monitor::proto::MonitorInfo monitor_info;
  //   auto soft_irq = monitor_info.add_soft_irq();
  //   soft_irq->set_cpu("cpu1");
  //   soft_irq->set_hi(100);
  //   soft_irq->set_timer(100);
  //   soft_irq->set_net_tx(100);
  //   soft_irq->set_net_rx(100);
  //   auto soft_irq2 = monitor_info.add_soft_irq();
  //   soft_irq2->set_cpu("cpu2");

  //   for (int i = 0; i < monitor_infos_.soft_irq_size(); i++) {
  //     std::cout << monitor_infos_.soft_irq(i).cpu() << " "
  //               << monitor_infos_.soft_irq(i).hi() << " "
  //               << monitor_infos_.soft_irq(i).timer() << " "
  //               << monitor_infos_.soft_irq(i).net_tx() << " "
  //               << monitor_infos_.soft_irq(i).net_rx() << " "
  //               << monitor_infos_.soft_irq(i).block() << " "
  //               << monitor_infos_.soft_irq(i).irq_poll() << std::endl;
  //   }
  *response = monitor_infos_;//将存储的监控信息赋值给响应对象。
  return grpc::Status::OK;
}

}  // namespace monitor

详细分析代码:
1、构造函数和析构函数
2、SetMonitorInfo 方法:**该方法接收来自客户端的 MonitorInfo 请求,并将其存储在类的成员变量 monitor_infos_ 中。**context:提供 gRPC 的上下文信息,可以访问元数据、取消状态等。request:客户端发送的 MonitorInfo 对象,包含监控信息。response:返回给客户端的响应,这里是一个空的 google::protobuf::Empty 对象。
3、GetMonitorInfo 方法:该方法返回之前存储在服务器端的 MonitorInfo 数据。context:同样提供 gRPC 的上下文信息。request:客户端发送的请求,这里是一个空的 google::protobuf::Empty 对象,表示不需要发送额外的数据。response:服务器返回的 MonitorInfo 对象,包含存储的监控信息。
SetMonitorInfo 方法:用于接受并存储来自客户端的监控信息。
GetMonitorInfo 方法:用于将存储的监控信息返回给客户端。

服务注册:在服务器端启动时,会将 GrpcManagerImpl 服务实例注册到 gRPC 服务器,客户端的请求将被分发到相应的方法上进行处理。

GrpcManagerImpl 是您创建的类,它继承自 GrpcManager::Service(由 .proto 文件生成的基类)并实现了其中的虚函数。GrpcManager::Service 是 protoc 编译器生成的类,定义了 RPC 方法的接口。
您需要在 GrpcManagerImpl 中编写实际的服务逻辑,将这些虚函数实现。这样,服务器端会使用 GrpcManagerImpl 来处理客户端的 RPC 调用。

rpc_manager.h

展示了 GrpcManagerImpl 类的定义,这是一个**继承自 gRPC 框架生成的 monitor::proto::GrpcManager::Service 类的实现类。**这个类负责处理客户端的 RPC 调用。

GrpcManagerImpl 类位于 monitor 命名空间内,继承自 monitor::proto::GrpcManager::Service,这是由 protoc 编译器生成的服务基类。

关于个自定义的GrpcManagerImpl 服务注册到服务器,我的理解

GrpcManagerImpl 服务被注册到服务器后,当客户端发送请求到服务器时,gRPC 框架会根据请求的内容自动调用 GrpcManagerImpl 类中的相应方法来处理请求,并生成响应。
具体过程如下:

客户端发送请求:
客户端通过存根(stub)调用 GrpcManagerImpl 服务中定义的 RPC 方法,并将请求数据打包成一个协议缓冲区(protobuf)消息。
服务器接收请求:
gRPC 框架在服务器端接收到这个请求,并根据请求中指定的服务和方法名,将请求分发到对应的 GrpcManagerImpl 实例。
调用服务方法:
服务器调用 GrpcManagerImpl 中对应的 RPC 方法来处理请求。这个方法会接受请求数据,进行相应的业务逻辑处理,并生成响应数据。
返回响应:
GrpcManagerImpl 的方法处理完请求后,将结果打包成一个协议缓冲区消息,并通过 gRPC 框架返回给客户端。
客户端接收响应:
客户端的存根接收到服务器的响应,并将响应数据解包,以供客户端使用。

gRPC 服务器允许你在同一个服务器实例中注册多个服务,这样客户端可以通过同一个服务器端点(IP地址和端口)访问不同的服务。
实例:假如有两个服务;

#include <grpc/grpc.h>
#include <grpcpp/server_builder.h>
#include "greeter_service_impl.h"
#include "calculator_service_impl.h"

void InitServer() {
  grpc::ServerBuilder builder;

  // 配置服务器监听的地址和端口
  builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials());

  // 创建服务实例
  GreeterServiceImpl greeter_service;
  CalculatorServiceImpl calculator_service;

  // 将服务实例注册到服务器构建器中
  builder.RegisterService(&greeter_service);
  builder.RegisterService(&calculator_service);

  // 构建并启动服务器
  std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
  std::cout << "Server started, listening on 0.0.0.0:50051" << std::endl;

  // 等待服务器关闭
  server->Wait();
}

int main() {
  InitServer();
  return 0;
}

处理客户端请求:当客户端发送请求时,gRPC 框架会根据请求的服务名和方法名,将请求分发给对应的服务实例和方法进行处理。
那客户端如何调用不同的服务呢?
客户端可以通过同一个服务器地址和端口访问不同的服务,只需要使用不同的存根(stub)来调用不同的服务方法。例如:
使用 GreeterService 的存根调用 SayHello 方法。
使用 CalculatorService 的存根调用 AddNumbers 方法。
通过注册多个服务实例,gRPC 服务器可以在同一个端点上提供多个服务,这样可以方便地扩展系统,支持多种功能和业务逻辑。

Client下

1、CMakeLists.txt

#
# Dependencies
#
# find_package(Threads)

#
# Sources
#
set(SOURCES
    # main.cpp
    rpc_client.cpp
)

# source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})

#
# Target
#
# add_executable(client ${SOURCES})
add_library(client  ${SOURCES})
target_link_libraries(client
    PUBLIC
    monitor_proto

)


# INSTALL(TARGETS client
#        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
#        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
#        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
# )

add_library(client ${SOURCES}) 指定使用 SOURCES 中的源文件创建一个名为 client 的库(动态库或静态库,取决于 CMake 的配置)。
这段 CMake 代码配置了一个名为 client 的库,并将 monitor_proto 链接到这个库中。这个库的主要源文件是 rpc_client.cpp,而不是一个可执行文件。

2、main.cpp

#pragma once

#include <string>
#include "rpc_client.h"
#include "monitor_info.grpc.pb.h"
#include "monitor_info.pb.h"

int main(int argc, char* argv[]) {
  // Setup request

  monitor::proto::MonitorInfo monitor_info;
  auto soft_irq = monitor_info.add_soft_irq();
  soft_irq->set_cpu("cpu1");
  auto soft_irq2 = monitor_info.add_soft_irq();
  soft_irq2->set_cpu("cpu2");

  monitor::RpcClient rpc_client;
  rpc_client.SetMonitorInfo(monitor_info);

  return 0;
}

这个代码实现了一个简单的 gRPC 客户端,向服务器发送一个 MonitorInfo 请求。它展示了如何创建和填充 Protocol Buffers 消息,以及如何使用自定义的 RpcClient 类与 gRPC 服务器进行通信。
这里创建了一个 MonitorInfo 对象 monitor_info。MonitorInfo 是在 monitor_info.proto 文件中定义的消息类型,
add_soft_irq() 方法用于向 monitor_info 中添加一个新的 SoftIrq 子消息。
set_cpu(“cpu1”) 设置第一个 SoftIrq 的 cpu 字段为 “cpu1”。
soft_irq2 是另一个 SoftIrq 对象,并且它的 cpu 字段被设置为 “cpu2”。
monitor::RpcClient 是你定义的客户端类的实例,用于与 gRPC 服务器通信。SetMonitorInfo(monitor_info) 是一个成员函数,发送 monitor_info 到服务器。这个函数封装了 gRPC 客户端调用的细节,包括将 monitor_info 序列化为 Protocol Buffers 消息并通过 gRPC 发送。

3、rpc_client.h/cpp

#pragma once

#include <grpc/grpc.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/grpcpp.h>

#include "monitor_info.grpc.pb.h"
#include "monitor_info.pb.h"

namespace monitor {
class RpcClient {
 public:
  RpcClient(const std::string& server_address = "localhost:50051");
  ~RpcClient();
  void SetMonitorInfo(const monitor::proto::MonitorInfo& monito_info);
  void GetMonitorInfo(monitor::proto::MonitorInfo* monito_info);

 private:
  std::unique_ptr<monitor::proto::GrpcManager::Stub> stub_ptr_;
};
}  // namespace monitor

定义了一个 monitor 命名空间中的 RpcClient 类,用于与 gRPC 服务器进行交互。
这段代码通过 gRPC 存根对象与服务器进行交互,分别实现了设置和获取监控信息的方法。成功与否的检查可以帮助调试和确保与服务器的通信正常。
1、构造函数

使用 grpc::CreateChannel 创建到服务器的 gRPC 通道,grpc::InsecureChannelCredentials 表示不需要身份验证的凭证。
使用创建的通道生成 GrpcManager 的存根对象 stub_ptr_,该对象用于与服务器进行交互。

2、SetMonitorInfo 方法:

创建一个 grpc::ClientContext 对象用于存储客户端上下文。
google::protobuf::Empty 用于接收服务器的空响应。
调用 stub_ptr_ 的 SetMonitorInfo 方法将 monito_info 发送到服务器,并接收空响应。

3、GetMonitorInfo 方法:

创建一个 grpc::ClientContext 对象用于存储客户端上下文。
google::protobuf::Empty 用于发送空请求。
调用 stub_ptr_ 的 GetMonitorInfo 方法向服务器发送请求,并将响应存储在 monito_info 中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值