protobuf学习日记 | 初识protobuf

目录

前言

一、序列化与反序列化

二、protobuf是什么

三、protobuf的使用特点

四、快速上手

1、proto文件编写

2、编译proto文件

3、序列化与反序列化的使用


前言

        这是小编新开的一个栏目,为了记录自己在学习ProtoBuf的历程,也希望能帮助大家,本栏目主要以一个通信录小项目的形式来学习protobuf,本文主要浅浅认识一下protobuf是什么?以及我们如何使用protobuf,并没有进阶内容,只是作为一个新手初步了解protobuf的过程;

一、序列化与反序列化

        在学习protobuf之前,大家都先得清楚一个概念,就是序列化与反序列化,这与我们接下来为什么学习protobuf有很大的关系;

序列化:把对象转换为字节序列的过程称为对象的序列化。

反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

应用场景:想必大家一定学习过网络编程吧?我们都知道,在进行网络传输过程中,我们一般不能传结构体,我们一般都传字符串等按字节为单位的数据,这是由于网络传输是跨主机的,不同主机可能出现不同的操作系统等不同标准,我们也听过一个概念就是大小端的概念,不同设备之间的标准也不同,若A主机按大端的方式将结构体传送给B主机,而B主机恰好为小端机器,那么这两者传输的数据就会出现异常,此时网络上就出现了网络字节序的概念,网络上的数据统一为大端,那么还有可能出现结构体对齐的问题,不同机器结构体对齐的标准也不同,因此就需要我们将数据进行序列化后再发送,接收端接收后,先进行反序列化得到结果;

二、protobuf是什么

        我们直接看官网对其进行的解释,如下所示;protobuf官网链接

翻译:

        Protocol Buffers是 Google 的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法,它可⽤于(数据)通信协议、数据存储等。

        Protocol Buffers 类⽐于 XML,是⼀种灵活,⾼效,⾃动化机制的结构数据序列化⽅法,但是⽐  XML 更⼩、更快、更为简单。

        你可以定义数据的结构,然后使⽤特殊⽣成的源代码轻松的在各种数据流中使⽤各种语⾔进⾏编写和读取结构数据。你甚⾄可以更新数据结构,⽽不破坏由旧数据结构编译的已部署程序。

        简单来说,protobuf 就是一种让结构数据序列化的方法,关于翻译中的特点,我们在后面学习中慢慢体会;

三、protobuf的使用特点

        我们使用proto文件定义结构对象(message)及属性,然后通过proto编译器编译后生成结构体对象对应的方法,如序列化与反序列化,其实生成的就是两个文件,一个头文件,一个源文件,这两个文件可以被我们主业务逻辑使用,就像我们平常引入头文件一样,如下图所示;

        看完上面这个你可能还有点懵,不过没关系,下面我会进行使用演示,看完使用演示后,你会对上面这张图有更清晰的认识;

四、快速上手

        在这里,我打算尝试演示一遍protobuf的使用,这里我打算做一个通讯录1.0版本,我将会实现如下;

  • 对⼀个联系⼈的信息使⽤ PB(protobuf) 进⾏序列化,并将结果打印出来。
  • 对序列化后的内容使⽤ PB(protobuf) 进⾏反序列,解析出联系⼈信息并打印出来。
  • 联系⼈包含以下信息: 姓名、年龄。

1、proto文件编写

        下面为我们所接触第一个段protobuf代码,我会对代码进行一一解释,具体如下所示;

// 注释
/* 注释 */
syntax = "proto3";  // 这是指定我们使用proto版本
package contacts;    // 指定一个命名空间

// 定义一个 message 结构
message PeopleInfo
{
    // 定义字段
    string name = 1;
    int32 age = 2;
}

(1)我们创建一个proto文件时,通常建议采用小写字母命名,且小写字母之间可以采用下划线分隔开来;如下所示

create_file

open_file

下图是我们这段代码的文件名

(2)注释有两种方法,如上述代码一二行,此注释方法与C语言、C++相同;

(3)我们使用关键字syntax来指定protobuf版本,这里一般指定proto3,若不写默认指定proto2;

(4)我们使用关键字package来指定一个命名空间,类似C++中的namespace,该命名空间作用于我们后续使用proto编译器编译该文件生成的文件代码作用域;

(5)我们使用关键字message来定义一个结构,其中结构中的字段用花括号括起来;

(6)我们定义的字段有不同的类型,上面分别为string类型与int32类型;每个字段都有一个字段编号,这个字段编号在该message中生效且唯一;(关于具体类型这里不做详细介绍,后面专门介绍)

(7)字段唯一编号我们推荐使用 15 3687 0911(2^29-1);其中范围1~15的字段我们进行编码需要一个字节,16~2047需要两个字节;这里的编码可理解成序列化;

2、编译proto文件

        我们通常使用如下命令进行编译proto文件;

protoc -I 要编译的proto文件所在目录   --cpp_out=生成文件所在目录   要编译的proto文件

        如上图我们编译完proto文件后,我指定的是当前目录,所以当前目录生成如下文件;

        没错,这些文件就是刚刚我们那个message结构对应的一些序列化、反序列化的方法;

3、序列化与反序列化的使用

        我们在上述目录下创建一个 mian.cc 的文件,保存我们接下来所编写主程序上的代码,如下所示,其中每一行都有注释;

// main.cc文件
#include <iostream>
#include <string>
#include "contacts.pb.h"

int main()
{
    // 1、对⼀个联系⼈的信息使⽤PB进⾏序列化,并将结果打印出来。

    // 定义PeopleInfor结构体(PB根据我们的proto文件帮我们生成的)
    contacts::PeopleInfo people;
    people.set_name("张三");
    people.set_age(19);
    // 定义接收序列化后字符串的缓冲区
    std::string people_str;
    // 序列化
    bool ret = people.SerializeToString(&people_str);
    if(ret == false)
    {
        std::cout << "序列化失败" << std::endl;
        exit(1);
    }
    printf("序列化成功,序列化后的结果为:\n%s", people_str.c_str());

    std::cout << "\n--------------------------- 分割线  ---------------------------\n";
    // 2、对序列化后的内容使⽤PB进⾏反序列,解析出联系⼈信息并打印出来。
    contacts::PeopleInfo destPeople;
    ret = destPeople.ParseFromString(people_str);
    if(ret == false)
    {
        std::cout << "反序列化失败" << std::endl;
        exit(2);
    }
    std::cout << "反序列化成功,结果为: " << std::endl
                << "name: " << destPeople.name() << std::endl
                << "age: " << destPeople.age() << std::endl;
    return 0;
}

        上述中我们使用序列化,反序列化的接口都来自于我们编译proto文件后自动帮我们生成的代码;一般来说,我们获取一个类字段的值用我们一开始在proto文件中message中给字段取得名字来获取字段的值,如上述中的name和age,设置字段的值一种加一个set,对于序列化一般以Serialize为开头,反序列化一般以Parse为开头,这里我们作为初体验仅仅记住上述所陈述即可;

        对于上述代码,我们必须使用g++进行编译时,必须加上如下特定选项;

-std=c++11    // 这是因为我们的protobuf帮我们生成的代码中使用c++11

-lprotobuf       // 因为protobuf为第三方库,我们必须指定库名

        我们直接运行,如下所示;

        这时,我们会发现我们序列化后的结果是一行空行加一个张三,这是因为我们序列化后的结果为一串二进制序列,这里用string进行接收,所以打印时会出现乱码;

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

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

相关文章

༺༽༾ཊ—设计-七个-07-原则-模式—ཏ༿༼༻

第七原则&#xff1a;迪米特职责 类与类之间的耦合度尽可能低 换言之&#xff0c;我们可以理解成———只与直接朋友说话&#xff0c;不跟陌生人说话 直接朋友&#xff1a; 通过方法传参传进来的朋友&#xff0c; 类自己的字段&#xff0c; 构造函数进来的也是直接朋友&…

CrystalDiskInfo v9.2.2

软件介绍 CrystalDiskInfo免费专业硬盘检测工具&#xff0c;硬盘健康状态信息检测工具。支持检测机械硬盘及固态硬盘信息&#xff0c;采用S.M.A.R.T.技术检测分析读取磁盘的详细信息&#xff0c;包含硬盘温度&#xff0c;固件、序列号、驱动器接口等。CrystalDiskInfo是由日本…

前沿重器[40] | 高级RAG技术——博客阅读

前沿重器 栏目主要给大家分享各种大厂、顶会的论文和分享&#xff0c;从中抽取关键精华的部分和大家分享&#xff0c;和大家一起把握前沿技术。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。&#xff08;算起来&#xff0c;专项启动已经…

回声状态网络(Echo State Networks,ESN)详细原理讲解及Python代码实现

回声状态网络&#xff08;Echo State Networks,ESN&#xff09;详细讲解及Python代码实现 1 基本概念 回声状态网络是一种循环神经网络。ESN 训练方式与传统 RNN 不同。网络结构如下图&#xff1a; &#xff08;1&#xff09;储层&#xff08;Reservoir&#xff09;&#x…

zotero使用gpt

zotero使用gpt 下载 zotero下载&#xff1a;https://www.zotero.org/download/ 插件下载&#xff1a;https://github.com/MuiseDestiny/zotero-gpt?tabreadme-ov-file 插件安装 zotero中选择 工具->添加组件 选择右上角的齿轮&#xff0c;选择Install add-on from fil…

LabVIEW水泵性能测试系

项目背景&#xff1a; 水泵作为工业和日常生活中不可或缺的设备&#xff0c;其性能测试对于提高设计水平和改善性能至关重要。传统测试方法往往需要依赖经验和理论的结合&#xff0c;且测试效率和准确性有待提高。为了解决这些问题&#xff0c;设计了一套基于NI-LabVIEW平台的水…

TikTok电商加快闭环,独享IP为运营带来哪些好处?

近日有消息称TikTok电商在加快闭环&#xff0c;以后商家可能无法继续在TikTok上为其他电商平台或独立站引流了。如今“TikTok Shop Shopping Center”平台正在构建&#xff0c;将各种购物渠道整合为一体&#xff0c;这可能是一种趋势&#xff0c;意味着TikTok逐渐从社交应用转型…

movie-web, 开源的电影搜索网站

这个开源的电影网站 movie-web 看起来是一个很不错的项目。它提供了简洁易用的界面&#xff0c;并且能够保存播放进度和收藏电影。同时&#xff0c;它还支持中文输入和快速的搜索响应速度&#xff0c;这对于中文用户来说是非常方便的。 不过需要注意的是&#xff0c;虽然它可以…

C# Cad2016二次开发api(三)

直线 Line 属性中文数据类型作用Length长度double直线的长度Angle角度double直线的弧度&#xff0c;0~2πDelta增量Vector3d起点到终点的向量Normal法向向量Vector3d直线所在平面的法向单位向量Thickness厚度doubleEndPoint终点Point3d直线的终点StartPoint起点Point3d直线的起…

使用Python实现深度学习模型通常涉及以下几个步骤:

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

RabbitMQ脑裂处理

脑裂现象&#xff1a; Network partition detected Mnesia reports that this RabbitMQ cluster has experienced a network partition. There is a risk of losing data. Please read RabbitMQ documentation about network partitions and the possible solutions. 转载请在文…

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(二)

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(二)。 技术架构是对某一技术问题(需求)解决方案的结构化描述,由构成解决方案的组件结构及之间的交互关系构成。广义上的技术架构是一系列涵盖多类技术问题设计方案的统称,例如部署方案、存储方案、缓存…

Centos系统安全设置

1 设置密码复杂度&#xff0c;帐号密码有效期3个月 密码复杂度要求&#xff1a;最小长度8位&#xff0c;至少2位大写字母&#xff0c;1位小写字母&#xff0c;4位数字&#xff0c;1位特殊字符 1&#xff09;执行备份&#xff1a; #cp -p /etc/login.defs /etc/login.defs_bak…

逸学Docker【java工程师基础】3.3Docker安装nacos

docker pull nacos/nacos-server docker network create nacos_network #创建容器网络 docker run -d \ --name nacos \ --privileged \ --cgroupns host \ --env JVM_XMX256m \ --env MODEstandalone \ --env JVM_XMS256m \ -p 8848:8848/tcp \ -p 9848:9848…

Linux 有哪些搜索方式?5分钟带你搞懂!

5分钟带你掌握 Linux 的三种搜索方式 前言 1.find 命令 find 命令是用来在给定的目录下查找符合给定条件的文件 语法格式&#xff1a;find [查找起始路径] [查找条件] [处理动作] &#xff08;1&#xff09;根据名称查找&#xff1a;find [查找起始路径] -name 文件名 或者…

​LeetCode解法汇总82. 删除排序链表中的重复元素 II

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给定一个已排序的链表的头 head &#xf…

request entity too large 解决请求实体过大问题的方法

在网络请求过程中&#xff0c;有时会出现请求实体过大而导致服务器无法处理的情况。本文将介绍两种情况及其解决办法&#xff0c;真实可用&#xff01; 问题描述 请求实体过大问题主要分为两种情况&#xff1a; 1、带413状态码的请求实体过大 这种情况通常发生在请求文件过…

09- OpenCV:图像上采样和降采样

目录 1、上采样和降采样 简介 2、采样的应用场景 3、采样的API 4、图像金字塔概念 5、代码演示 1、上采样和降采样 简介 在图像处理中&#xff0c;上采样&#xff08;Upsampling&#xff09;和降采样&#xff08;Downsampling&#xff09;是常用的操作。 &#xff08;1&…

React函数式组件学习笔记

React是一种用于构建用户界面的JavaScript库&#xff0c;它采用组件化的方式来构建复杂的UI。在React中&#xff0c;函数式组件是一种声明式的方式去描述UI的状态和行为。 React的特性 1.声明式设计-React采用声明范式&#xff0c;可以轻松描述应用 2.高效-React通过对DOM的模…

若依顶部导航栏改造

若依顶部导航栏改造 1.改造后代码 需要代码的请私聊我&#xff01; 目前的话就是三级目录&#xff0c;太多了也没啥用&#xff01;