protobuf学习使用

1、概述

protobuf是Google开发的一种语言中立、平台无关、可扩展的序列化结构数据格式。允许定义一次数据结构,然后可以使用各种支持的语言来生成代码,以轻松地读写这些结构到一个二进制流中,如网络传输或文件,Protobuf支持多种编程语言,包括但不限于C++、Java、Python、Go、Ruby、JavaScript、C#等。

protobuf-getting-started:Protocol Buffer Basics: C++ | Protocol Buffers Documentation

2、使用步骤(以C++举例)

1、创建并编写xxx.proto文件

        将要序列化的数据写到proto文件

2、将proto文件生成对应的.cc和.h文件

        protoc -I=/路径1 --cpp_out=./路径2 /路径1/addressbook.proto

        路径1为.proto所在的路径

        路径2为.cc和.h⽣成的位置
protoc.exe -I=./ --cpp_out=./ *.proto

 3、直接使用新生成的类

        里边有对数据操作的api

3、使用说明

3.1、编写xxx.proto文件  

举例login.proto

// 声明protobuf版本
syntax = "proto3";

// 定义请求消息
message LoginRequest {
  // 语法格式:字段类型 字段名 = 字段编号;
  // 编号从1开始,不能重复
  bytes username = 1;
  string password = 2;
  int32 type = 3;
}

// 定义响应消息
message LoginResponse {
  string token = 1;
  bytes message = 2;
}

message相当于C++的class关键字,LoginRequest相当于类名,注释采用C/C++风格的双斜杠(//)

username、password、type相当于成员变量。编号从1开始,不能重复,序列化后的protobuf没有使用字段名称,而仅仅采用了字段编号区分字段,与json xml等相比,protobuf不是一种完全自描述的协议格式,即接收端在没有proto文件定义的前提下是无法解码一个protobuf消息体的,与此相对的,json xml等协议格式是完全自描述的,拿到了json消息体,便可以知道这段消息体中有哪些字段。

语法格式
字段类型 字段名 = 字段编号

如何知道有哪些字段类型呢,可以对照下面表查看

3.2、将proto文件生成对应的.cc和.h文件

protoc -I=./ --cpp_out=./ *.proto

其中login.pb.h和login.pb.cc为新生成的头文件和源文件。
下载链接比如:https://github.com/protocolbuffers/protobuf/releases/tag/v26.1

此时我们可以打开看看新生成的头文件,会发现其中有相关字段读写api,详见下图:

3.3、使用代码范例

范例代码演示了如何使用新生成的类,如何序列化和反序列化

代码编译:g++ -std=c++11 -o main login.pb.cc main.cc -lprotobuf -lpthread -L/usr/local/lib

#include "login.pb.h"
#include <iostream>
using namespace std;

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

    // 创建一个 LoginRequest 对象
    LoginRequest login_request;
    login_request.set_username("张三");
    login_request.set_password("123");
    login_request.set_type(100);

    // 将 LoginRequest 对象序列化为字符串
    string request_data;
    login_request.SerializeToString(&request_data);

    // 将字符串发送到服务器....

    // 服务器接收到字符串后,反序列化为 LoginRequest 对象
    LoginRequest login_response;
    login_response.ParseFromString(request_data);

    // 使用 LoginRequest 对象进行业务逻辑处理...
    cout << "接收 用户名: " << login_response.username() << endl;
    cout << "接收 密码: " << login_response.password() << endl;
    cout << "接收 类型: " << login_response.type() << endl;

    return 0;
}

4、protobuf中使用数组

使用数组要使用repeated修饰相关字段,此时你可以理解为vector<string> name,如图。

#include "login.pb.h"
#include <iostream>
using namespace std;

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

    // 创建一个 LoginRequest 对象
    LoginRequest login_request;
    // login_request.set_username("张三");

    // username 是一个 repeated 字段,可以添加多个用户名
    login_request.add_username("张三");
    login_request.add_username("李四");
    login_request.add_username("王五");

    login_request.set_password("123");
    login_request.set_type(100);

    // 将 LoginRequest 对象序列化为字符串
    string request_data;
    login_request.SerializeToString(&request_data);

    // 将字符串发送到服务器....

    // 服务器接收到字符串后,反序列化为 LoginRequest 对象
    LoginRequest login_response;
    login_response.ParseFromString(request_data);

    // 使用 LoginRequest 对象进行业务逻辑处理...
    // cout << "接收 用户名: " << login_response.username() << endl;
    cout << "接收 用户名: " << login_response.username(0) << endl;
    cout << "接收 用户名: " << login_response.username(1) << endl;
    cout << "接收 用户名: " << login_response.username(2) << endl;

    cout << "接收 密码: " << login_response.password() << endl;
    cout << "接收 类型: " << login_response.type() << endl;

    return 0;
}

5、protobuf中使用枚举

在proto文件中添加枚举定义(如图),这里有一个注意事项,枚举的第一个元素值必须为0,为了兼容proto2语义。

#include "login.pb.h"
#include <iostream>
using namespace std;

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

    // 创建一个 LoginRequest 对象
    LoginRequest login_request;
    // login_request.set_username("张三");

    // username 是一个 repeated 字段,可以添加多个用户名
    login_request.add_username("张三");
    login_request.add_username("李四");
    login_request.add_username("王五");

    login_request.set_password("123");
    login_request.set_type(100);

    // 设置枚举值
    login_request.set_logintype(ADMIN);

    // 将 LoginRequest 对象序列化为字符串
    string request_data;
    login_request.SerializeToString(&request_data);

    // 将字符串发送到服务器....

    // 服务器接收到字符串后,反序列化为 LoginRequest 对象
    LoginRequest login_response;
    login_response.ParseFromString(request_data);

    // 使用 LoginRequest 对象进行业务逻辑处理...
    // cout << "接收 用户名: " << login_response.username() << endl;
    cout << "接收 用户名: " << login_response.username(0) << endl;
    cout << "接收 用户名: " << login_response.username(1) << endl;
    cout << "接收 用户名: " << login_response.username(2) << endl;

    cout << "接收 密码: " << login_response.password() << endl;
    cout << "接收 类型: " << login_response.type() << endl;

    // 打印 枚举登陆类型
    cout << "接收 类型: " << login_response.logintype() << endl;

    return 0;
}

6、protobuf中导入其他proto文件

新编写extrainfo.proto,使用import导入,然后使用protoc工具生成新头文件和源文件。
范例代码演示了如何操作Extrainfo中的成员。
备注:相关接口在生成的头文件中都能看到,可以打开看看

代码编译:g++ -std=c++11 -o main login.pb.cc main.cc extrainfo.pb.cc -lprotobuf -lpthread -L/usr/local/lib

// 声明protobuf版本
syntax = "proto3";

message Extrainfo {
  string time = 1;
  int32 level = 2;
}
// 声明protobuf版本
syntax = "proto3";
// 导入其他proto文件
import "extrainfo.proto";

enum LoginType {
  USER = 0; // proto3中第一个枚举值必须为0
  ADMIN = 1;
}

// 定义请求消息
message LoginRequest {
  // 语法格式:字段类型 字段名 = 字段编号;
  // 编号从1开始,不能重复
  repeated bytes username = 1;
  string password = 2;
  int32 type = 3;
  LoginType loginType = 4;
  Extrainfo extra = 5;
}

// 定义响应消息
message LoginResponse {
  string token = 1;
  bytes message = 2;
}
#include "login.pb.h"
#include <iostream>
using namespace std;

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

    // 创建一个 LoginRequest 对象
    IMLogin::LoginRequest login_request;
    // login_request.set_username("张三");

    // username 是一个 repeated 字段,可以添加多个用户名
    login_request.add_username("张三");
    login_request.add_username("李四");
    login_request.add_username("王五");

    login_request.set_password("123");
    login_request.set_type(100);

    // 设置枚举值
    login_request.set_logintype(ADMIN);

    // 操作其他proto,extra字段
    login_request.mutable_extra()->set_time("key");
    login_request.mutable_extra()->set_level(6);

    // 将 LoginRequest 对象序列化为字符串
    string request_data;
    login_request.SerializeToString(&request_data);

    // 将字符串发送到服务器....

    // 服务器接收到字符串后,反序列化为 LoginRequest 对象
    LoginRequest login_response;
    Extrainfo extra = login_response.extra();
    login_response.ParseFromString(request_data);

    // 使用 LoginRequest 对象进行业务逻辑处理...
    // cout << "接收 用户名: " << login_response.username() << endl;
    cout << "接收 用户名: " << login_response.username(0) << endl;
    cout << "接收 用户名: " << login_response.username(1) << endl;
    cout << "接收 用户名: " << login_response.username(2) << endl;

    cout << "接收 密码: " << login_response.password() << endl;
    cout << "接收 类型: " << login_response.type() << endl;

    // 打印 枚举登陆类型
    cout << "接收 类型: " << login_response.logintype() << endl;

    // 访问其他proto,extra字段
    cout << "接收 extra 字段: " << extra.time() << endl;
    cout << "接收 extra 字段: " << extra.level() << endl;

    return 0;
}

7、protobuf中添加命名空间

在proto文件中添加package IMLogin,表示当前的proto文件命名空间为IMLogin,打开生成的头文件一看就懂,C++代码再定义对象时也要添加上命名空间。

8、protobuf编译安装

9、问题:使用protobuf为什么节省字节

1、变量名不用传递,传编号(按编号区分字段)

2、采用可变长字段方案(可自行了解下)

学习链接:https://github.com/0voice

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/943421.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CTFHUB-web进阶-php

我们用蚁剑中的这个插件来做这些关卡 一.LD_PRELOAD 发现这里有一句话木马&#xff0c;并且把ant给了我们&#xff0c;我们直接连接蚁剑 右键 选择模式&#xff0c;都可以试一下&#xff0c;这里第一个就可以 点击开始 我们进入到目录&#xff0c;刷新一下&#xff0c;会有一个…

相机、镜头参数详解以及相关计算公式

一、工业相机参数 1、分辨率 相机每次采集图像的像素点数&#xff0c;也是指这个相机总共有多少个感光晶片。在采集图像时&#xff0c;相机的分辨率对检测精度有很大的影响&#xff0c;在对同样打的视场成像时&#xff0c;分辨率越高&#xff0c;对细节的展示越明显。 相机像素…

取多个集合的交集

1.我们取多个集合的交集&#xff0c;先把各个集合放入list中 List < Set < String > > listnew ArrayList<>();HashSet<String> set1new HashSet<>();set1.add( "A" );set1.add("B" );set1.add("C" );HashSet<…

leetcode之hot100---206环形链表(C++)

思路一&#xff1a;哈希表 遍历链表&#xff0c;同时借助哈希表判断当前遍历到的节点是否已经被访问过&#xff0c;如果当前节点已被访问过&#xff0c;则说明存在环 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* L…

文档解析丨高效准确的PDF解析工具,赋能企业非结构化数据治理

在数据为王的时代浪潮中&#xff0c;企业数据治理已成为组织优化运营、提高竞争力的关键。随着数字化进程的加速&#xff0c;企业所积累的数据量呈爆炸式增长&#xff0c;数据类型也愈发多样化&#xff0c;这些数据构成了现代企业数据资产的重要组成部分。 然而&#xff0c;传…

优化 invite_codes 表的 SQL 创建语句

-- auto-generated definition create table invite_codes (id int auto_incrementprimary key,invite_code varchar(6) not null comment 邀请码&#xff0c;6位整数&#xff0c;确保在有效期内…

C语言基础:指针(数组指针与指针数组)

数组指针与指针数组 数组指针 概念&#xff1a;数组指针是指向数组的指针&#xff0c;本质上还是指针 特点&#xff1a; 先有数组&#xff0c;后有指针 它指向的是一个完整的数组 一维数组指针&#xff1a; 语法&#xff1a; 数据类型 (*指针变量名)[行容量][列容量]; 案…

进阶篇(1)

一.存储引擎: <1>MySQL体系结构: 1.连接层: 主要接收客户端的连接,完成一些连接的处理、认证授权、及相关操作安全方案、检测是否超过最大连接数等等;也会为安全接入的每个客户端验证它所具有的操作权限。 例如:在连接MySQL服务器时,我们需要输入用户名和密码,输…

电脑提示报错NetLoad.dll文件丢失或损坏?是什么原因?

一、NetLoad.dll文件丢失或损坏的根源 程序安装不完整&#xff1a;某些程序在安装过程中可能因为磁盘错误、网络中断或安装程序本身的缺陷&#xff0c;导致NetLoad.dll文件未能正确安装或复制。 恶意软件攻击&#xff1a;病毒、木马等恶意软件可能会篡改或删除系统文件&#x…

uniapp使用live-pusher实现模拟人脸识别效果

需求&#xff1a; 1、前端实现模拟用户人脸识别&#xff0c;识别成功后抓取视频流或认证的一张静态图给服务端。 2、服务端调用第三方活体认证接口&#xff0c;验证前端传递的人脸是否存在&#xff0c;把认证结果反馈给前端。 3、前端根据服务端返回的状态&#xff0c;显示在…

UE5仿漫威争锋灵蝶冲刺技能

这两天玩了一下漫威争锋Marvel Rivals&#xff0c;发现是UE5做的&#xff0c;对里面一些角色技能挺感兴趣的&#xff0c;想简单复刻一下技能功能&#xff0c;顺便复习一下学过的知识 首先把摄像机设置调整一下 CameraBoom里搜索lag 把摄像机延迟关掉 &#xff0c;这样摄像机就…

去除 el-input 输入框的边框(element-ui@2.15.13)

dgqdgqdeMac-mini spid-admin % yarn list --pattern element-ui yarn list v1.22.22 └─ element-ui2.15.13 ✨ Done in 0.23s.dgqdgqdeMac-mini spid-admin % yarn list vue yarn list v1.22.22 warning Filtering by arguments is deprecated. Please use the pattern opt…

Suno Api V4模型无水印开发「综合实战开发自己的音乐网站」 —— 「Suno Api系列」第14篇

历史文章 Suno AI API接入 - 将AI音乐接入到自己的产品中&#xff0c;支持120并发任务 Suno Api V4模型无水印开发「灵感模式」 —— 「Suno Api系列」第1篇 Suno Api V4模型无水印开发「自定义模式」 —— 「Suno Api系列」第2篇 Suno Api V4模型无水印开发「AI生成歌词」…

企业如何搭建安全的跨网文件安全交换管理系统

在数字化转型的浪潮中&#xff0c;企业对数据的安全性和流动性提出了前所未有的高要求。特别是在网络隔离的情况下&#xff0c;如何实现跨网的安全、高效的文件交换成为了众多企业迫切需要解决的问题。 这不仅是技术上的挑战&#xff0c;还涉及到企业内部管理流程的优化和安全策…

Torch.gather

1.官方文档 2.使用要点 输入index的shape等于输出value的shape输入index的索引值仅替换该index中对应dim的index值最终输出为替换index后在原tensor中的值 最终输出的shape和index的shape相同 根据dim的值 选择将index[i,j,k]这个结果替换input[i,j,k]里面对应的i or j or…

报警推送消息升级的名厨亮灶开源了

简介 AI视频监控平台, 是一款功能强大且简单易用的实时算法视频监控系统。愿景在最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;减少企业级应用约 95%的开发成本&#xff0c;在强大视频算法加…

《解锁 Python 数据挖掘的奥秘》

《解锁 Python 数据挖掘的奥秘》 一、Python 数据挖掘基础&#xff08;一&#xff09;Python 基础与数据挖掘环境搭建&#xff08;二&#xff09;数据挖掘基本流程概述 二、Python 数据挖掘核心技术&#xff08;一&#xff09;数据收集与预处理技术&#xff08;二&#xff09;常…

如何通过 360 驱动大师检查自己电脑上的显卡信息

在深入探讨如何查看显卡信息之前&#xff0c;首先需要了解显卡的基本概念。显卡&#xff08;Graphics Processing Unit, GPU&#xff09;&#xff0c;是计算机中负责处理图形输出到显示器的重要硬件。根据其集成度和性能&#xff0c;显卡通常被分为两类&#xff1a; 集成显卡&…

深度学习目标检测算法之RetinaNet算法

文章目录 前言RetinaNet 算法原理1.RetinaNet 简介2.backbone 部分3.FPN特征金字塔4.分类和预测5.Focal Loss 结束语 &#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注…

[源码解析] 模型并行分布式训练Megatron (2) --- 整体架构

link [源码解析] 模型并行分布式训练Megatron (2) --- 整体架构 目录 [源码解析] 模型并行分布式训练Megatron (2) --- 整体架构 0x00 摘要0x01 启动 1.1 分布式启动1.2 构造基础 1.2.1 获取模型1.2.2 获取数据集1.2.3 步进函数 1.2.3.1 广播数据0x02 Pretrain0x03 初始化 3.1 …