安装、学习protobuf

protobuf · 浏览次数 : 0

小编点评

The provided context describes how to compile a C++ project that depends on a protobuf file. Here's a summary: **Compilation process:** 1. **Generate C++ source files and header files:** `protoc --cpp_out=. $<#` compiles the protobuf file into C++ source and header files. 2. **Clean:** `rm -f $(TARGET) test.pb.cc test.pb.h` removes any existing generated C++ source and header files. 3. **Build the program:** `makeg++ -I. -L/user/local/lib -lprotobuf -std=gnu++11 run.cpp test.pb.cc -o run[root@hcss-ecs-9452 test_proto]` builds the program with the compiled source and library files. 4. **Run the program:** `./runname` runs the built program with the name specified in `runname`. **Dependencies:** - The program depends on a protobuf file named `testComplex.proto`. - This file is not included in the code snippet provided. **Additional notes:** - The code uses a `Color` enum to represent different colors. - It demonstrates how to use an enum in the `Person` struct. - The `SerializeToString()` method is used to convert the `Person` object to a string for serialization. - The `ParseFromString()` method is used to convert a string to a `Person` object. **Overall, this code demonstrates how to build and run a C++ program that interacts with a protobuf file by importing and using its types and structures.**

正文

Protobuf是什么?

类似于json的一种数据格式,独立于语言,而且是二进制方式,所以比json更快,而且还可以直接存储一些图、树

序列化和反序列化

持久化(存到磁盘硬盘)领域中,数据存到磁盘叫序列化,从磁盘读取出来叫反序列化
网络传输领域中,数据块转字符串叫序列化,对端把字符串解析为数据块叫反序列化

客户端和服务端如何通信

比如一个结构体三个数据依次发送出去,接收端可能一下接收了三个,是无法处理的(不知道边界)
第二种情况,一次性发送出去,添加标记,这样接收端可以一次性解封装,常采用TLV (Tag Length Value)

Protobuf到底是什么

类似于刚刚说的TLV结构,是一种组织数据的格式,可以把若干数据组织成一块---> 序列化为字符串 --> 发送 --> 字符串被反序列化 --> 解析数据

Protobuf怎么安装?

只演示Linux下的安装过程

  1. github下载tar.gz包

https://github.com/protocolbuffers/protobuf/releases/tag/v21.12

我这里下载的21.12版本,比较老了,但是基本功能都能用

image

  1. 登录Linux服务器安装

先上传到Linux上,一般的ssh工具如Mobaxterm都有这个功能

tar -zxvf your_protobuf_package.tar.gz -C /path/to/you_want

cd /path/to/you_want

  • 需要安装c++编译器,如果其他语言版本的也要安装对应编译器,c++我用的g++编译器!

./configure

make

sudo make install

protoc --version

Protobuf如何使用?

简单示例

  1. 确定要序列化的数据,手动改成protobuf格式
Protobuf类型 c++类型 备注
double double 64位浮点数
float float 32位浮点数
int32 int 32位整数
int64 long 64位整数
uint32 unsigned int 32位无符号整数
uint64 unsigned long 64位无符号整数
sint32 signed int 32位整数,处理负数效率高于int32
sint64 signed long 64位整数,处理负数效率高于int64
bool bool 布尔
string string 字符串必须是utf-8或7-bit ASCII编码
bytes string 多字节语言,比如中文字符,用这个更好
enum enum 枚举
message object of class 自定义消息类型
  1. 根据proto语法,写入后缀proto文件中

test.proto

[root@hcss-ecs-9452 test_proto]# cat test.proto 
/*
struct Person
{
    string name;
    string sex;
    int age;
}
*/
syntax = "proto3";

message Person
{
    string name = 1;
    bytes sex = 2;
    int32 age = 3;
}
  1. protoc命令把proto文件转成c++,包含一个xxx.pb.cc和xxx.pb.h

protoc ./test.proto --cpp_out=./

[root@hcss-ecs-9452 test_proto]# 
[root@hcss-ecs-9452 test_proto]# ls
test.proto
[root@hcss-ecs-9452 test_proto]# protoc ./test.proto --cpp_out=./
[root@hcss-ecs-9452 test_proto]# ls
test.pb.cc  test.pb.h  test.proto
[root@hcss-ecs-9452 test_proto]#
  1. 把产生的c++文件添加到项目中,根据文件中API实现序列化和反序列化

节选test.pb.h ,这部分就是protobuf给出的对name这个数据的处理方式,比如清空 设置 查询 根据地址修改等

enum : int {
    kNameFieldNumber = 1,
    kSexFieldNumber = 2,
    kAgeFieldNumber = 3,
  };
  // string name = 1;
  void clear_name();
  const std::string& name() const;
  template <typename ArgT0 = const std::string&, typename... ArgT>
  void set_name(ArgT0&& arg0, ArgT... args);
  std::string* mutable_name();
  PROTOBUF_NODISCARD std::string* release_name();
  void set_allocated_name(std::string* name);
  private:
  const std::string& _internal_name() const;
  inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
  std::string* _internal_mutable_name();

  1. 编写makefile

这里需要注意,protobuf大量使用c++11特性,但是centOS默认安装的是g++4.8.5编译器,可能不支持,需要在编译选项中-std=gnu++11

# 目标文件
TARGET = run

# 源文件
SRC = run.cpp test.pb.cc

# 编译器
CC = g++

# 编译选项
CFLAGS = -I. -lprotobuf -std=gnu++11

# 默认规则
all: $(TARGET)

# 依赖关系
$(TARGET): $(SRC)
        $(CC) $(CFLAGS) $^ -o $@

# 编译.proto文件生成C++源文件和头文件
test.pb.cc test.pb.h: test.proto
        protoc --cpp_out=. $<

# 清理规则
clean:
        rm -f $(TARGET) test.pb.cc test.pb.h

# 防止make删除中间文件
.PHONY: all clean

  1. 编译运行查看

可能要先设置一下环境变量

echo $LD_LIBRARY_PATH

# 如果已经设置过/usr/local/lib就不用往下走了
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib' >> ~/.bashrc

source ~/.bashrc

echo $LD_LIBRARY_PATH
[root@hcss-ecs-9452 test_proto]# ls
Makefile  run.cpp  test.pb.cc  test.pb.h  test.proto
[root@hcss-ecs-9452 test_proto]# make
g++ -I. -L/user/local/lib -lprotobuf -std=gnu++11 run.cpp test.pb.cc -o run
[root@hcss-ecs-9452 test_proto]# ./run
name:Jack
sex:女
age:18

复杂应用

嵌套复合数据类型

新增一个proto文件,后续步骤和上面一致

  • 嵌套结构体直接加,嵌套数组前面加repeated就行,调用时需注意,数组要先add_xxx, set_xxx(0, xx)
[root@hcss-ecs-9452 test_proto]# cat testComplex.proto 
syntax = "proto3";
message Addr
{
    int32 door_num = 1;
    bytes addr     = 2;
}

message Person
{
    repeated string name = 1;
    bytes sex   = 2;
    int32 age   = 3;
    Addr ad     = 4;
}
[root@hcss-ecs-9452 test_proto]# cat run.cpp
#include "testComplex.pb.h"

int main(){

    Person p1;
    p1.add_name();
    p1.set_name(0, "Jack");
    p1.add_name("Tom");
    p1.add_name("sb");
   
    p1.set_sex("女");
    p1.set_age(18);
    p1.mutable_ad()->set_addr("陕西省西安市雁塔区");
    p1.mutable_ad()->set_door_num(999); 
    
    std::string output;
    p1.SerializeToString(&output);
    
    Person p2;
    p2.ParseFromString(output);
    //std::cout << "name:" << p2.name() << std::endl;
    std::cout << "sex:"  << p2.sex() << std::endl;
    std::cout << "age:"  << p2.age() << std::endl;
    std::cout << "addr:" << p2.ad().addr() << p2.ad().door_num() << "号" << std::endl;
    int size = p2.name_size();
    for(int i = 0; i < size; ++i)
    {
        std::cout << "第" << i << "个名字是" << p2.name(i) << std::endl;
    }
    return 0;
}

使用枚举


[root@hcss-ecs-9452 test_proto]# cat testComplex.proto 
syntax = "proto3";
enum Color
{
    red = 0;    //第一个必须是0
    green = 5;  //后面的不必123
    blue = 6;
}
message Addr
{
    int32 door_num = 1;
    bytes addr     = 2;
}

message Person
{
    repeated string name = 1;
    bytes sex   = 2;
    int32 age   = 3;
    Addr ad     = 4;
    Color color = 9;  //这里也可以不写567
}
[root@hcss-ecs-9452 test_proto]# cat run.cpp
#include "testComplex.pb.h"

int main(){

    Person p1;
    p1.add_name();
    p1.set_name(0, "Jack");
    p1.add_name("Tom");
    p1.add_name("sb");
   
    p1.set_sex("女");
    p1.set_age(18);
    p1.mutable_ad()->set_addr("陕西省西安市雁塔区");
    p1.mutable_ad()->set_door_num(999); 
    p1.set_color(Color::red);    
 
    std::string output;
    p1.SerializeToString(&output);
    
    Person p2;
    p2.ParseFromString(output);
    //std::cout << "name:" << p2.name() << std::endl;
    std::cout << "sex:"  << p2.sex() << std::endl;
    std::cout << "age:"  << p2.age() << std::endl;
    std::cout << "addr:" << p2.ad().addr() << p2.ad().door_num() << "号" << std::endl;
    int size = p2.name_size();
    for(int i = 0; i < size; ++i)
    {
        std::cout << "第" << i << "个名字是" << p2.name(i) << std::endl;
    }
    std::cout << "Color:"  << p2.color() << std::endl;
    return 0;
}

proto中导入其他proto文件

import "/path/xxx.proto"

命名空间

package xxx

  • 当其他proto文件调用时:
    xxx.Person p

  • 上述命令会转换为cc文件的namespace

与安装、学习protobuf相似的内容:

安装、学习protobuf

Protobuf是什么? 类似于json的一种数据格式,独立于语言,而且是二进制方式,所以比json更快,而且还可以直接存储一些图、树 序列化和反序列化 持久化(存到磁盘硬盘)领域中,数据存到磁盘叫序列化,从磁盘读取出来叫反序列化 网络传输领域中,数据块转字符串叫序列化,对端把字符串解析为数据块叫反

用StabilityMatrix一键安装Stable Diffusion

Stable Diffusion是2022年发布的深度学习文字到图像生成模型,它既能免费使用,又能部署在本地端,又有非常多的模型可以直接套用,在使用体验上比Midjourney和DALL-E更加强大。Stable Diffusion使用的模型有下列几大类,对照模型网站 https://civitai

安装Amos结构方程模型分析软件的方法

本文介绍IBM SPSS Amos软件的安装方法~

Redis7.0.7的简单安装与学习

Redis7.0.7的简单安装与学习 摘要 2022.12.18 世界杯决赛 另外是我感染奥密克戎第五天. 高烧已经没了,但是嗓子巨疼. 睡不着觉,肝胆学习一下最新的Redis7.0.7 第一部分安装 现在最新的stable 的安装包地址为: http://download.redis.io/red

Anaconda安装Python的seaborn库

本文介绍在Anaconda的环境中,安装Python语言中,常用的一个绘图库seaborn模块的方法。 seaborn模块是基于Matplotlib的数据可视化库,它提供了一种更简单、更漂亮的界面来创建各种统计图形。seaborn模块主要用于数据探索、数据分析和数据可视化,使得我们在Python中创

使用Docker安装Odoo 17(非Docker Compose)

使用Docker安装Odoo 17(非Docker Compose) 前言 最近在学习Odoo,先是windows 安装企业版,多年不用windows的服务器操作系统,一看windows的ECS那么贵就想折腾一下用linux服务器来跑Odoo社区版.于是开始实践,这篇文件只记录结果。其中趟坑的滋味暂

ArcMap安装OSM路网数据编辑插件ArcGIS Editor for OSM的方法

本文介绍在ArcGIS下属的ArcMap软件中,ArcGIS Editor for OpenStreetMap这一工具集插件的下载与安装的具体方法~

在虚拟机VMware上安装OpenKylin开源操作系统

# 在虚拟机(VMware)上安装OpenKylin开源操作系统 今天我们一下学习下开放麒麟系统的安装。也是我的开源项目在OpenKylin上运行的实践。 希望通过该项目了解和学习Avalonia开发的朋友可以在我的github上拉取代码,同时希望大家多多点点star。 https://github

下载、安装CAN-EYE植被参数工具

本文介绍植被指数计算软件CAN-EYE的下载、安装方法。 CAN-EYE软件是由法国国家农业研究院(French National Institute of Agricultural Research,INRA)下属的EMMAH实验室(Mediterranean Environment and Ag

在Ubuntu系统安装Anaconda及Python

本文介绍在Linux Ubuntu操作系统的电脑中,安装Anaconda环境与Python语言的方法。 在之前的文章Anaconda与Python环境在Windows中的部署中,我们介绍了在Win10电脑中,安装Anaconda环境与Python语言的方法;而在本文中,我们就详细介绍一下在Linux