Protobuf入门

Protobuf介绍

Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

Protobuf应用实例

在一个main函数里实现protobuf的输入、序列化、反序列化、输出。

项目结构

创建工作空间文件夹protobuf_test,并在protobuf_socket下创建必要的文件。

mkdir protobuf_test
touch addressbook.proto
touch main.cpp

文件目录如下所示
在这里插入图片描述

编写addressbook.proto文件

// Filename: addressbook.proto

syntax="proto2";  //protobuf的编译器版本为v2
package addressbook; //声明包名,防止不同的消息类型命名冲突,类似于 amespace 

//message是Protobuf中的结构化数据,类似于C++中的类,可以在其中定义需要处理的数据

//protobuf一共有三个字段修饰符:
//  - required:该值是必须要设置的;
//  - optional :该字段可以有0个或1个值(不超过1个);
//  - repeated:该字段可以重复任意多次(包括0次),类似于C++中的list;
message Person {
    required string name = 1; //声明了一个名为name,数据类型为string的required字段,字段的标识号为1
    required int32 id = 2;
    optional string email = 3;

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

    message PhoneNumber {
        required string number = 1;
        optional PhoneType type = 2 [default = HOME]; //为type字段指定了一个默认值,当没有为type设值时,其值为HOME
    }

    repeated PhoneNumber phone = 4;
}

//一个proto文件中可以声明多个message,在编译的时候他们会被编译成为不同的类
message AddressBook {
    repeated Person person_info = 1;
}

编译addressbook.proto文件

protoc -I=. --cpp_out=. addressbook.proto

编译之后会生成两个文件addressbook.pb.cc 和 addressbook.pb.h
在这里插入图片描述

编写main.cpp文件

#include <iostream>
#include "addressbook.pb.h"

int main(int argc, const char* argv[])
{
    addressbook::AddressBook person;
    addressbook::Person* pi = person.add_person_info();

    pi->set_name("ttr");
    pi->set_id(1219);
    std::cout << "before clear(), id = " << pi->id() << std::endl;
    pi->clear_id();
    std::cout << "after  clear(), id = " << pi->id() << std::endl;
    pi->set_id(3520);
    if (!pi->has_email())
        pi->set_email("ttr@momenta.edu,cn");

    addressbook::Person::PhoneNumber* pn = pi->add_phone();
    pn->set_number("123456789");
    pn = pi->add_phone();
    pn->set_number("987654321");
    pn->set_type(addressbook::Person::WORK);

    //序列化,输出到字节流
    uint32_t size = person.ByteSizeLong(); //获取二进制字节序大小
    unsigned char byteArray[size];  //开辟空间存储字节流
    person.SerializeToArray(byteArray, size);
    //反序列化
    addressbook::AddressBook help_person;
    help_person.ParseFromArray(byteArray, size);
    addressbook::Person help_pi = help_person.person_info(0);

    std::cout << "*****************************" << std::endl;
    std::cout << "id:    " << help_pi.id() << std::endl;
    std::cout << "name:  " << help_pi.name() << std::endl;
    std::cout << "email: " << help_pi.email() << std::endl;

    for (int i = 0; i < help_pi.phone_size(); ++i)
    {
        auto help_pn = help_pi.mutable_phone(i);
        std::cout << "phone_type: " << help_pn->type() << std::endl;
        std::cout << "phone_number: " << help_pn->number() << std::endl;
    }
    std::cout << "*****************************" << std::endl;

    return 0;
}

常用API

protoc为message的每个required字段和optional字段都定义了以下几个函数(不限于这几个):

TypeName xxx() const;          //获取字段的值
bool has_xxx();              //判断是否设值
void set_xxx(const TypeName&);   //设值
void clear_xxx();          //使其变为默认值

为每个repeated字段定义了以下几个:

TypeName* add_xxx();        //增加结点
TypeName xxx(int) const;    //获取指定序号的结点,类似于C++的"[]"运算符
TypeName* mutable_xxx(int); //类似于上一个,但是获取的是指针
int xxx_size();            //获取结点的数量

另外,下面几个是常用的序列化函数:

bool SerializeToOstream(std::ostream * output) const; //输出到输出流中
bool SerializeToString(string * output) const;        //输出到string
bool SerializeToArray(void * data, int size) const;   //输出到字节流

与之对应的反序列化函数:

bool ParseFromIstream(std::istream * input);     //从输入流解析
bool ParseFromString(const string & data);       //从string解析
bool ParseFromArray(const void * data, int size); //从字节流解析

其他常用的函数:

bool IsInitialized();    //检查是否所有required字段都被设值
size_t ByteSizeLong() const; //获取二进制字节序的大小

官方API文档地址: https://developers.google.com/protocol-buffers/docs/reference/overview

编译main.cpp与addressbook.pb.h文件

g++ -o main main.cpp addressbook.pb.cc -lprotobuf -pthread 

生成main可执行文件,执行之:

运行结果

在这里插入图片描述

参考大神文档

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值