当前位置: 首页 > news >正文

pb生成文件和反射

1.protoc生成文件

指定生成的目录和proto文件路径,

protoc --cpp_out=./ ./echo.proto
// echo.proto
syntax = "proto3";package echo;option cc_generic_services = true;message EchoRequest {string msg = 1;
}message EchoResponse {string msg = 2;
}service EchoService {rpc Echo(EchoRequest) returns (EchoResponse);
}

使用 protoc 命令编译 .proto 文件时,会生成两个主要的 C++ 文件:

  1. echo.pb.h(头文件)
  2. echo.pb.cc(源文件)

1.1 pb头文件

echo.pb.h 是 Protocol Buffers 自动生成的头文件,主要用于声明消息(message类型)的类、方法、枚举以及相关的类型信息,还有服务类(Service类)。它的内容包含以下几个部分:

  • 类声明:为每个 .proto 文件中的消息定义一个对应的 C++ 类。例如,如果你在 .proto 文件中定义了一个 Message 类型,头文件中会生成一个 Message 类。

  • 字段的访问器和修改器方法:每个消息类中的字段都会有 getter 和 setter 函数。这些函数用于访问和修改 Protocol Buffers 消息中的字段。例如,set_field()field()clear_field() 等函数。

  • // 序列化和反序列化函数:包含用于将消息对象序列化为二进制格式或从二进制格式反序列化的函数。常见的方法包括 SerializeToString()ParseFromString()。// 这个实际不在生成的文件中。

  • 其他辅助函数:如比较函数(operator==),清理函数(Clear()),以及元数据函数(例如 descriptor())。

服务类类型:

服务类 EchoService 是一个抽象类,声明了服务器端和客户端接口,具体如下:

  • 服务端接口:EchoService::Echo() 是一个虚函数,必须在服务器端的实现类中进行具体的定义。服务器端代码需要继承这个类并实现其中的 Echo() 方法。
class EchoService : public ::grpc::Service {public:virtual ~EchoService();// Abstract method to be implemented on the server sidevirtual ::grpc::Status Echo(::grpc::ServerContext* context,const EchoRequest* request,EchoResponse* response) = 0;// Method to register the service with a gRPC server::grpc::ServerUnaryCallHandlerFactoryBase<EchoRequest, EchoResponse>* RegisterEcho();// Other methods for service registration and reflection
};

服务器端实现:服务器端需要继承 EchoService 类并实现 Echo() 方法。例如:

class MyEchoServiceImpl : public EchoService {::grpc::Status Echo(::grpc::ServerContext* context, const EchoRequest* request, EchoResponse* response) override {// Implement your logic hereresponse->set_msg("Response to: " + request->msg());return ::grpc::Status::OK;}
};
  • 客户端接口Stub 是客户端调用远程 RPC 服务的接口,声明如下。客户端代码通过 Stub 调用 Echo() 方法进行远程调用,发送请求并接收响应。
class EchoService::Stub : public ::grpc::Client {public:// Method to invoke the RPC from the client::grpc::Status Echo(::grpc::ClientContext* context, const EchoRequest& request, EchoResponse* response);
};

1.2 pb源文件

echo.pb.cc 是 Protocol Buffers 自动生成的源文件,主要包含消息类方法的实现。它是 echo.pb.h 中声明的方法的具体定义。源文件的内容主要包括:

  • 构造函数和析构函数:消息类的构造函数、析构函数,以及复制构造函数等。

  • 字段访问器和修改器的实现:具体实现 pb.h 文件中声明的 getter 和 setter 函数,用于访问和修改pb 消息中的字段。

  • 序列化和反序列化的实现:具体实现序列化和反序列化的方法,例如 SerializeToArray()ParseFromArray() 等。

  • 字段的内存管理:管理动态分配的内存(如果消息包含嵌套消息或 repeated 字段)。

  • 消息的元数据:通常包含与消息相关的反射信息,用于支持 Protocol Buffers 的动态功能(如反射系统,descriptor 元数据等)。

2.pb反射机制

Protocol Buffers 的反射机制允许你在运行时动态地操作消息对象,而无需在编译时明确知道其类型或字段。// 可以认为能获取到元数据的机制就是反射机制。

反射使得开发者可以在运行时通过一种通用的方式来操纵 Protocol Buffers 消息,包括:

  1. 获取消息的元数据(如字段的名称、类型等)。
  2. 动态访问和修改消息的字段,即使这些字段在编译时是未知的。
  3. 遍历所有的字段,包括已设置的和未设置的字段。
  4. 动态序列化和反序列化消息,无需依赖具体的消息类型。

反射机制特别适合以下场景:

  • 通用工具或框架:如调试器、序列化框架、消息检查工具等,使用反射可以处理多种不同的消息类型。
  • 不确定消息类型的情况下:如当消息的类型在运行时才能确定时(例如在 RPC 系统中使用动态消息分发)。
const google::protobuf::Descriptor* descriptor = echo::EchoRequest::descriptor();
std::cout << descriptor->name();  // 打印消息名称
  • 在这个例子中,descriptor() 方法返回的是 EchoRequest 消息的描述符,通过它可以获取消息的名称、字段的数量等信息。
echo::EchoRequest req;
req.set_msg("Hello, World!");// 返回反射对象
const google::protobuf::Reflection* reflection = req.GetReflection();
// 通过字段名称获取 FieldDescriptor
const google::protobuf::FieldDescriptor* field = req.descriptor()->FindFieldByName("msg");// 通过反射获取字段的值
std::string value = reflection->GetString(req, field);
std::cout << "msg field value: " << value << std::endl;

反射对象通过描述符与消息的实际实例交互。通过反射对象,你可以在运行时获取和设置消息字段的值,而不需要直接访问消息对象的成员函数

其他常用的反射操作:

// 获取字段值
int32_t id_value = reflection->GetInt32(message, field_descriptor);// 设置字段值
reflection->SetString(&message, field_descriptor, "New Value");// 检查字段是否已设置
if (reflection->HasField(message, field_descriptor)) {// 字段已设置
}// 清除字段
reflection->ClearField(&message, field_descriptor);

// 看起来还是要知道字段名和类型。

2.1 动态消息遍历

const google::protobuf::Descriptor* descriptor = req.descriptor();
const google::protobuf::Reflection* reflection = req.GetReflection();for (int i = 0; i < descriptor->field_count(); ++i) {const google::protobuf::FieldDescriptor* field = descriptor->field(i);if (field->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {std::string value = reflection->GetString(req, field);std::cout << field->name() << ": " << value << std::endl;}
}

使用 field_count() 获取消息的字段总数,然后遍历每个字段,检查字段类型并获取其值。

// 但感觉这里有点怪怪的,reflection指针是从req返回的,但是reflection调用自己成员函数的时候还要把req传进去。

相关文章:

pb生成文件和反射

1.protoc生成文件 指定生成的目录和proto文件路径&#xff0c; protoc --cpp_out./ ./echo.proto // echo.proto syntax "proto3";package echo;option cc_generic_services true;message EchoRequest {string msg 1; }message EchoResponse {string msg 2; }…...

.net framework 3.5sp1安装错误卡住不动怎么解决

解决 .NET Framework 3.5 SP1 安装错误卡住的问题&#xff0c;可以尝试以下几种方法&#xff1a; 1.使用 DISM 工具&#xff1a; 将下载的 NetFx3.cab 文件放置在 C:\Windows 文件夹下。 以管理员身份打开命令提示符&#xff0c;输入以下命令&#xff1a; dism /online /En…...

毕业设计—基于 Inception-ResNet模型的皮肤癌分类系统实现

1.摘要 皮肤癌是人类最常见的恶性肿瘤&#xff0c;主要通过视觉诊断进行初步临床筛查。但是由于皮肤病变外观的细微变化性&#xff0c;使用图像自动分类皮肤病变是一项具有挑战性的任务。本文为了提高深度学习算法在皮肤病检测上的准确率&#xff0c;本文提出了基于Inception和…...

什么是优秀的单元测试?

阅读本文之前&#xff0c;请投票支持这款 全新设计的脚手架 &#xff0c;让 Java 再次伟大&#xff01; 单元测试的质量意义 合理编写单元测试&#xff0c;可使团队工程师告别牛仔式编程&#xff0c;产出易维护的高质量代码。随着单元测试覆盖率的上升&#xff0c;项目会更加…...

服务器安装Anaconda,Anaconda安装Pytorch

1.服务器安装Anaconda 1.1 下载Anaconda 在服务器上直接下载 wget https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh1.2 安装Anaconda bash Anaconda3-2024.06-1-Linux-x86_64.sh然后就显示下面&#xff1a;more 安装过程一直enter即可&#xff0c;…...

YOLO目标检测理论详解,YOLOv1理论知识讲解,超w字精读(学习YOLO框架必备),全网最详细教程

文章目录 前言一、目标检测理论1.目标检测发展史2.目标检测框架理论基础3.本章小结 二、YOLOv1理论知识1.YOLOv1网络结构2.YOLOv1检测原理3.YOLOv1的训练流程&#xff08;1&#xff09;边界框的位置参数&#xff08;2&#xff09;边界框的置信度&#xff08;3&#xff09;类别置…...

SpringBoot3.x和OCR构建车牌识别系统

本专题旨在展示 OCR 技术与 SpringBoot3.x 框架结合的广泛应用。我们会深入探讨它在医疗、金融、教育、交通、零售、公安等多个领域的现实应用。每个应用场景都会提供详细的实例、面临问题的分析与解决策略&#xff0c;以帮助您深入理解 OCR 技术在实践中的关键作用。让我们一同…...

conda 容器学习笔记之一 -- 基础环境配置

1、容器瘦身导致部分应用缺少&#xff0c;需要在非容器环境下部署环境。但为避免破坏现有环境&#xff0c;现有使用conda环境进行隔离管理 创建&#xff1a;conda create -n tts python3.10.0 2、conda 是python环境管理&#xff0c;和python无关的东西比如cann还是会影响 下载…...

Oracle分区表改造(三):通过分区交换和分裂改造为分区表

Oracle分区表改造(三):通过分区交换和分裂改造为分区表 源表数据准备范围分区表改造:非间隔分区创建普通分区表分区交换分区分裂范围分区表改造:间隔分区创建间隔分区表分区交换分区分裂表重命名🐬 创建只有一个分区的分区表, 通过分区交换将原表变成分区表,然后分裂分…...

LeetCode 0908.最小差值 I:思维(遍历)

【LetMeFly】908.最小差值 I&#xff1a;思维&#xff08;遍历&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/smallest-range-i/ 给你一个整数数组 nums&#xff0c;和一个整数 k 。 在一个操作中&#xff0c;您可以选择 0 < i < nums.length 的…...

Python基础之循环语句

在Python的编程世界里&#xff0c;循环结构犹如一把神奇的钥匙&#xff0c;开启高效处理数据和重复执行任务的大门。它赋予程序员强大的力量&#xff0c;让代码充满活力。Python主要有两种类型的循环语句&#xff1a;for循环和while循环。 一、for循环 for循环通常用于遍历一个…...

项目管理软件真的能让敏捷开发变得更简单吗?

敏捷开发是一种以快速交付和适应变化为核心特点的软件开发方法。其特点包括尽早并持续交付、能够驾驭需求变化、版本周期内尽量不加任务、业务与开发协同工作、以人为核心、团队配置敏捷等。 例如&#xff0c;尽早并持续交付可使用的软件&#xff0c;使客户能够更早地体验产品…...

互联网名称之时间戳

什么是时间戳 时间戳&#xff08;Timestamp&#xff09;是一种用于表示特定时刻的数值或字符串&#xff0c;通常以日期和时间的形式出现。它用于记录某一事件发生的准确时间&#xff0c;在计算机系统中常被用于日志记录、数据处理和同步等场景。 常见的时间戳 在互联网中常见…...

Leetcode—1242. 多线程网页爬虫【中等】Plus(多线程)

2024每日刷题&#xff08;187&#xff09; Leetcode—1242. 多线程网页爬虫 实现代码 /*** // This is the HtmlParsers API interface.* // You should not implement it, or speculate about its implementation* class HtmlParser {* public:* vector<string>…...

RISC-V笔记——内存模型总结

1 前言 Memory consistency model定义了使用Shared memory(共享内存)执行多线程(Multithread)程序所允许的行为规范。RISC-V使用的内存模型是RVWMO(RISC-V Weak Memory Ordering)&#xff0c;RVWMO内存模型是根据全局内存顺序(global memory order)定义的&#xff0c;全局内存…...

后端常用安全措施

一、限流 1.简介 限流就是限制流量&#xff0c;但这里的流量是一个比较笼统的概念。如果考虑各种不同的场景&#xff0c;限流是非常复杂的&#xff0c;而且和具体的业务规则密切相关 通过限流&#xff0c;可以控制服务请求的速率&#xff0c;从而提高系统应对突发大流量的能…...

虚拟机数据恢复—通过拼接数据库页碎片的方式恢复数据库的数据恢复案例

虚拟机数据恢复环境&#xff1a; 某品牌服务器通过同品牌某型号的RAID卡&#xff0c;将4块STAT硬盘为一组RAID10阵列。上层部署XenServer虚拟化平台&#xff0c;虚拟机安装Windows Server系统&#xff0c;每台虚拟机有两个虚拟机磁盘&#xff08;系统盘 数据盘&#xff09;&am…...

【vue】自封组件,基于vue2封装一个弹框组件

源码&#xff1a;https://download.csdn.net/download/galaxyJING/89913551...

ES6基础知识

一、定义变量的关键字let和const 1. let 定义变量的语法&#xff1a; let 变量名 值; 2. 和var定义变量的区别 1. 是否支持同一个作用域变量同名 var支持&#xff0c;let不支持 2. 是否支持预解析 var支持&#xff0c;let不支持 3. 是否会挂载在window对象…...

基于Multisim的模拟拔河游戏比赛设计与仿真

1.设计一个模拟拔河游戏比赛的逻辑电路 2.使用15个发光二极管表示绳子&#xff0c;开机后只有最中间的发光二极管亮。 3.比赛双方各持一个按钮&#xff0c;快速不断地按动按钮&#xff0c;产生脉冲&#xff0c;谁按的快&#xff0c;发光的二极管就向谁的方向移动&#xff0c;每…...

MyBatis 配置详解

在项目中经常会用到 mybatis 相关的一些配置&#xff0c;而在启动类项目工程中&#xff0c;一般会把 mybatis 配置文件单独写到 mybatis,yml 中&#xff0c;如下简单介绍下常用的 mybatis 配置 mybatis:configuration:call-setters-on-nulls: truemap-underscore-to-camel-case…...

研发运营一体化(DevOps)能力成熟度模型

目录 应用设计 安全风险管理 技术运 持续交付 敏捷开发管理 基于微服务的端到端持续交付流水线案例 应用设计 安全风险管理 技术运 持续交付...

躺平成长-利用kimi编辑助手帮助自己编程第二天

天有道&#xff0c;无常道&#xff0c;兵无常势。 {今天开始听歌&#xff08;歌曲&#xff1a;青丝&#xff01;&#xff09;进行编程&#xff01;} 尝试用ai帮助自己进行小程序的开发&#xff0c;同时最为关键&#xff0c;是无法能够完成相关的代码的记忆&#xff0c;所以我开…...

OpenSuse-搭建NFS-Server

在OpenSUSE上搭建NFS服务可以通过以下步骤完成&#xff1a; ### 1. 安装NFS服务器软件 首先&#xff0c;确保你已经安装了NFS服务器软件包。你可以使用zypper命令来安装&#xff1a; sudo zypper install nfs-kernel-server### 2. 配置NFS导出目录 编辑/etc/exports文件&#x…...

【数据结构与算法】之二分查找

二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元素的搜索算法。它通过比较数组中间元素与目标值来工作&#xff0c;从而将搜索范围缩小到一半&#xff0c;也称折半查找&#xff0c;是一种非常高效的工作于有序数组的查找算法。本文主要介绍二分查找…...

vue修饰符

表单修饰符 1、lazy <input type "text" v-model.lazy "value"> <p>{{value}}</p>lazy跟懒加载类似&#xff0c;只有再说鼠标离开光标的时候才会触发&#xff0c;也就是说在input事件的oninput书法的时候不会赋值&#xff0c;当onch…...

Oracle里面,with ... as 用法介绍

在Oracle数据库中&#xff0c;WITH AS 子句&#xff08;也称为公用表表达式&#xff0c;CTE, Common Table Expression&#xff09;是一种在查询中定义临时结果集的方法。这个临时结果集可以在后续的查询中被引用&#xff0c;就像是一个临时的表或视图一样。使用 WITH AS 子句可…...

一个简单的Qt Console Application计算练习程序

初步体验Qt Creator 用途&#xff1a;练习20以内2位数乘法速算的程序 功能1&#xff1a;支持用户设定题目数量 std::cout << "请输入本次练习题目数量&#xff1a;";int numProblems 0;std::string num;std::cin >> num;try {numProblems std::stoi(…...

windows文件拷贝给wsl2的Ubuntu

参考&#xff1a; windows文件如何直接拖拽到wsl中_win 移到文件到wsl-CSDN博客 cp -r /mnt/盘名/目标文件 要复制到wsl中的位置e.g.cp -r /mnt/d/byt5 /home Linux文件复制、移动、删除等操作命令_linux移动命令-CSDN博客 Linux 文件、文件夹的复制、移动、删除 - Be-myse…...

vivado 采用 SSI 器件进行设计

SSI 管脚的考虑因素 在为特定 SLR 中的组件规划管脚时&#xff0c;请将引脚放置在同一个 SLR 中。例如&#xff0c;将器件的 DNA 信息作为外部接口的一部分 时&#xff0c;请将该接口的引脚放置在 DNA_PORT 所在的主 SLR 中。其它考虑因素包括如下&#xff1a; • 把…...