首页 > 其他分享 >protobuf安装、使用

protobuf安装、使用

时间:2023-04-16 10:33:36浏览次数:52  
标签:set string phone Student 使用 PATH 安装 protobuf

介绍

protobuf是用来对数据进行序列化和反序列化的灵活,高效,自动化的解决方案。

序列化:将数据结构转换成二进制的字节串
反序列化:将二进制串还原成数据结构

Ubuntu下编译安装

尝试安装最新版本-v3.22.1(没成功)

参照文档的安装过程
github-protocol-readme

这里在Linux下使用cmake构建,找到readm中指示的cmake的readme.md
protocol-cmake-readme

#下载源码和子模块
$ git clone https://github.com/protocolbuffers/protobuf.git
$ cd protobuf
$ git submodule update --init --recursive

#在源码路径下开始编译
$ cmake .
$ cmake --build . --parallel 10

#安装
$ sudo make install

使用:

编译时一直报错:asbl::相关的undefined,没有找到原因。
也许不应该编译submodule中的abseil-cpp模块

换版本安装-v3.20.1

网友们使用的版本大都是带初始化脚本然后再编译,我也尝试下载之前的版本进行编译

去proto git的release界面下载了v3.20.1版本源码
将之前版本残留的文件删除,默认在/usr/local/的include\lib\bin目录下

$ ./autogen.sh
报错
./autogen.sh: 41: autoreconf: not found
安装前置
$ sudo apt-get install autoconf automake libtool

##
$ ./autogen.sh
$ ./configure --prefix=/usr/local/comenv/protobuf

$ make -j4
$ sudo make install
#可以看到在指定路径下生成了lib\bin\include三个目录

#配置系统环境 or 配置工程使用环境
$ sudo vi /etc/profile

#添加:
export PATH=$PATH:/usr/local/comenv/protobuf/bin/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/comenv/protobuf/lib
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/comenv/protobuf/lib
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/comenv/protobuf/include
export PKG_CONFIG_PATH=/usr/local/comenv/protobuf/lib/pkgconfig

#PATH                 可执行文件查找目录
#LD_LIBRARY_PATH      动态链接器(ld)查找动态库的路径,即执行期间的库文件查找路径
#LIBRARY_PATH         编译期间库查找路径
#CPLUS_INCLUDE_PATH   g++头文件查找路径
#PKG_CONFIG_PATH      pc文件查找路径

# 或者不修改环境,只修改自己工程的查找路径
# 使用时也可以只修改工程编译选项的库、头文件路径,只是在代码IDE里就没有提示、跳转识别等

$ source /etc/comenv

参考
csdn - wangicter

or

命令行安装-没试过

sudo apt insatll protobuf-compiler libprotobuf-dev

验证

$ protoc --version
libprotoc 3.20.1

使用

一般步骤

以C++为例

  • 创建proto文件,定义数据格式等
  • 使用protoc工具,将proto文件编译生成一个.h和.cc文件,将源\头文件拷贝至工程使用
  • 使用protobuf的接口,实现序列号、反序列化

protoc编译工具

$ protoc --cpp_out=./xxx/ ./xxx.proto
#--cpp_out表示将proto文件编译出c++使用的.cc和.h,并指定文件输出的路径
#最后一个参数是proto文件路径
#编译之后,程序包含生成的cc和h文件即可使用

proto文件

syntax = "proto3";

package SCH; //整个文件的包名,对应到C++里是这个文件所有的message类都在这个命名空间里

message Student{
  //选项 类型 名称 = 标号
  uint64 id = 1;
  string name =2;
  optional string email = 3;

  enum PhoneType {
      MOBILE = 0;
      HOME = 1;
  }

  message PhoneNumber {
      string number = 1;
      optional PhoneType type = 2;
  }
  repeated PhoneNumber phone = 4;

  message Remark { 
    string describe = 1;
    int32  rank = 2;
  }

  Remark remark = 5;
}
  • syntax 使用的proto的版本,2和3有一些语法差别,不写默认为版本2

  • package 防止不同项目之间的命名冲突。对应到C++中,这个文件生成的类将被放置在一个与package名相同的命名空间中。

  • message 消息结构定义,一个message就是一些字段的集合,字段可以是bool\int32\double\string等基础类型,也可以是其他message类型。这里Student和PhoneNumber都会在程序中作为类名。

    • message中,字段的格式为:修饰符 类型 名称 = 标识;
  • 修饰符 message中的每个字段都有一个修饰符(可以缺省)

    • optional 可选的,加入这个标识,会生成has_xx的接口
    • repeated 可重复的(可以理解为不定长的数组)
  • 标识 该字段在二进制编码中使用的唯一“标识(tag)”。标识号1-15编码所需的字节数比更大的标识号使用的字节数要少1个,所以,如果你想寻求优化,可以为经常使用或者重复的项采用1-15的标识(tag),其他经常使用的optional项采用≥16的标识(tag)。在重复的字段中,每一项都要求重编码标识号(tag number),所以重复的字段特别适用于这种优化情况。

调用接口

查看头文件中字段生成的接口:

//这里省略了很多
// uint64 id = 1;
void Student::clear_id();
uint64_t Student::id();
void Student::set_id(uint64_t value);

// string name = 2;
inline void Student::clear_name();
inline const std::string& Student::name();
template <typename ArgT0, typename... ArgT>
inline void Student::set_name(ArgT0&& arg0, ArgT... args);
inline std::string* Student::mutable_name();
inline std::string* Student::release_name();

// repeated .SCH.Student.PhoneNumber phone = 4;
inline int Student::phone_size()
inline void Student::clear_phone()
inline ::SCH::Student_PhoneNumber* Student::mutable_phone(int index)
inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::SCH::Student_PhoneNumber >* Student::mutable_phone()
inline const ::SCH::Student_PhoneNumber& Student::phone(int index)
inline ::SCH::Student_PhoneNumber* Student::add_phone()
inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::SCH::Student_PhoneNumber >& Student::phone()
  • 普通字段都有set_xxx、clear_xxx和xxx的接口,xxx是定义的字段名称,set_id()就是给id字段赋值,id()就是获取id字段的值
  • string字段比普通字段多了mutable_xxx的接口,nutable_name()返回name字段buf的指针,为空时调用这个接口会初始化一个空字符串
  • 可重复字段,多了xxx_size和add_xxx接口,取消了set_xxx接口。并且xxx()和mutable_xxx接口有了重载,可以根据index索引来获取/设置指定位置的内容。add_phone接口返回一个初始化后的字段指针,并添加到phone buf中,利用这个指针进行赋值。

标准接口

string DebugString() const; //将消息内容以可读的方式输出

bool SerializeToString(string* output) const; //将消息序列化并储存在指定的string中。注意里面的内容是二进制的,而不是文本;我们只是使用string作为一个很方便的容器。

bool ParseFromString(const string& data); //从给定的string解析消息。

bool SerializeToArray(void * data, int size) const  //将消息序列化至数组

bool ParseFromArray(const void * data, int size)    //从数组解析消息

bool SerializeToOstream(ostream* output) const; //将消息写入到给定的C++ ostream中。

bool ParseFromIstream(istream* input); //从给定的C++ istream解析消息。

序列号、反序列化示例

#include <iostream>
#include <string>
#include "hello.pb.h"

//序列化
int serialize(std::string &resStr) {
    SCH::Student stu;

    //向对象中填值
    stu.set_id(23456);   //普通成员会有set函数来赋值
    stu.set_name("stu1");
    *stu.mutable_email() = "[email protected]";  //string成员会多一些接口,mutable会返回指针

    //嵌套的重复成员:
    SCH::Student::PhoneNumber* pNum1 = stu.add_phone();
    pNum1->set_number("1812435454");
    pNum1->set_type( SCH::Student::MOBILE);

    SCH::Student::PhoneNumber* pNum2 = stu.add_phone();
    pNum2->set_number("1234567");
    pNum2->set_type( SCH::Student::HOME);

    //嵌套的单次成员
    stu.mutable_remark()->set_describe("ok");
    stu.mutable_remark()->set_rank(1);

    //将stu序列化到string中,string中数据已经是二进制的格式,string只是它的容器
    stu.SerializePartialToString(&resStr);

    std::cout << "Serialize, debug string: \n" << stu.DebugString() << std::endl;  //按照结构输出
    return 0;
}

//反序列化
int deserialize(std::string &str) {
    SCH::Student stu;
    if ( false == stu.ParseFromString(str) ) {
        std::cout << "parse failed" << std::endl;
        return -1;
    }

    std::cout << "Deserialize, debug string: \n" << stu.DebugString() << std::endl;
    std::cout << "-------------" << std::endl;


    if (stu.has_email()) {  //设置为optional的字段才会有这个接口
        std::cout << "email: " << stu.email() << std::endl;
    }
    std::cout << "id: " << stu.id() << std::endl;

    for (int i=0; i<stu.phone_size(); i++) {
        SCH::Student::PhoneNumber pnum = stu.phone(i);
        pnum.has_type();

        std::cout << "phone: " << pnum.type() << "-" << pnum.number() << std::endl;
    }
    return 0;
}

int main() {
    std::string SerializeStr;

    serialize( SerializeStr);
    std::cout << "----------" << std::endl;
    deserialize(SerializeStr);

    return 0;
}

编译选项需要链接:
-lprotobuf -lpthread

参考
腾讯云 - Dabelv
csdn - freshman94

标签:set,string,phone,Student,使用,PATH,安装,protobuf
From: https://www.cnblogs.com/TaXueWuYun/p/17322623.html

相关文章

  • 1378. 使用唯一标识码替换员工ID
    【题目】Employees表:+---------------+---------+|ColumnName  |Type   |+---------------+---------+|id           |int    ||name         |varchar|+---------------+---------+id是这张表的主键。这张表的每一行分别代表了某公......
  • SQLyog Ultimate软件安装教程
    目录一、软件介绍二、软件下载三、软件安装 (1)首先下载云盘中的SQLyog-12.0.8-0.x64.exe (2)双击执行SQLyog-12.0.8-0.x64.exe文件,点击OK (3)选择下一步 (4)勾选协议,然后选择下一步 (5)更换软件安装位置,默认是安装到C盘的,建议安装到其它磁盘。  (6)等待安装完成 (7)选择UI(用户界面)语言......
  • dockerfile的使用,使用dockerfile部署springboot项目
    文章目录一、dockerfile概述1、dockerfile基础2、Docker执行Dockerfile的大致流程3、镜像、容器、dockerfile的关系二、dockerfile常用保留字1、FROM2、MAINTAINER与LABEL3、RUN4、EXPOSE5、WORKDIR6、USER7、ENV8、ADD9、COPY10、VOLUME11、CMD12、ENTRYPOINT三、使用dockerfile构......
  • 使用 APT-mirror 四步配置 Ubuntu 本地软件仓库
    我们将向你展示如何在你的Ubuntu个人电脑或Ubuntu服务器中,直接通过Ubuntu官方软件仓库来配置本地软件仓库。在你的电脑中创建一个本地软件仓库有着许多的好处。假如你有许多电脑需要安装软件、安全升级和修复补丁,那么配置一个本地软件仓库是一个做这些事情的高效方法。......
  • Arrays工具类的使用
    java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。比如:数组元素拼接:      staticStringtoString(int[]a):字符串表示形式由数组的元素列表组成,括在方括号("[]")中。相邻元素用字符","(逗号加空格)分隔。形式为:[元素1,元素2,元素3......
  • ffmpeg安装及使用
    ffmpegAcomplete,cross-platformsolutiontorecord,convertandstreamaudioandvideo官网:http://ffmpeg.org/安装linux下安装aptinstallffmpegffmpeg-hwindows下安装下载地址https://github.com/BtbN/FFmpeg-Builds/releases下载后解压配置环境变量设......
  • Linux学习安装
    ncpa.cpl查看网络连接1、安装Vmware注意事项:版本不匹配[(24条消息)创建Linux报错“与vmx86驱动程序的版本不匹配:预期为410.0,实际为360.0”_vmx86驱动程序的版本不匹配_学习学习学习,再学习的博客-CSDN博客](https://blog.csdn.net/qq_54132332/article/details/123......
  • heatmapts_simple-heatmap的使用
    simpleheat的使用<scriptsetuplang="ts">import{SimpleHeat}from"simpleheat-ts";import*asdatfrom"dat.gui";letframe:number|null=null;constoCanvas=document.createElement("canvas");oCanva......
  • 使用ThreadLocal请务必remove
    原文地址:https://www.cnblogs.com/panchanggui/p/15105419.html特别注意,web容器的线程是重复使用的,web容器使用了线程池,当一个请求使用完某个线程,该线程会放回线程池被其它请求使用,这就导致一个问题,不同的请求还是有可能会使用到同一个线程(只要请求数量大于线程数量),而ThreadLocal......
  • git 使用
    创建分支:gitcheckout-bXXX提交到分支gitaddgitcommit-m""gitpushoriginXXX分支名创建标签taggit tag XXXtagnamegitpushoriginXXXtagname切换到分支或标签gitcheckouttagname/branchname......