在macOS上使用Protobuff

0x00 什么是Protocol Buffers?

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。
Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

你可以理解为Protocol Buffers就是用来替代我们常见的json&xml等数据交换格式的。

pb优点:

◇性能好 / 效率高
◇代码生成机制 – 这个后面说
◇支持 “向后兼容” 和 “向前兼容”
◇支持多种编程语言

Protobuf 的不足:

◇Protbuf 与 XML 相比也有不足之处。它功能简单,无法用来表示复杂的概念。
◇XML 已经成为多种行业标准的编写工具,Protobuf 只是 Google 公司内部使用的工具,在通用性上还差很多。

0x01 macOS安装Protocol Buffers

brew install protobuf

0x02 使用 ProtoBuf

使用Protobuf有如下几个步骤:

  • 定义消息
  • 初始化消息以及存储传输消息
  • 读取消息并解析

以git上的此项目,为例来进行说明:

第一步,创建 .proto 文件,定义数据结构,如下所示:

syntax = "proto2";

package lm;
message helloworld
{
    required int32 id=1;
    optional string str=2;
    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
      }
    message PhoneNumber {
        optional string number = 1;
        optional PhoneType type = 2;
      }
    repeated PhoneNumber phones = 4;
}

关于 proto2 定义 message 消息的更多语法细节,例如具有支持哪些类型,字段编号分配、import
导入定义,reserved 保留字段等知识请参阅 [翻译] ProtoBuf 官方文档(二)- 语法指引(proto2)。

第二步,protoc 编译 .proto 文件生成读写接口

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/hello.proto
  • -I: 是设定源路径
  • –cpp_out: 用于设定编译后的输出结果,如果使用其它语言请使用对应语言
  • option 最后一个参数是你要编译的proto源文件

使用该命令会在同级目录下生成pb.cc和pb.h文件

-rw-r--r--  1 tesi1a  staff   27616  7 22 01:35 hello.pb.cc
-rw-r--r--  1 tesi1a  staff   31257  7 22 01:35 hello.pb.h

已经定义好了消息的数据结构,接下来看下如何使用。

第三步,调用接口实现序列化、反序列化以及读写

#include "hello.pb.h"
#include 
#include 
#include 

using namespace std;
bool writeBuf(string file_path)
{
    lm::helloworld msg1;
    lm::helloworld::PhoneNumber *phone;
    msg1.set_id(100);
    msg1.set_str("200");

    phone = msg1.add_phones();
    phone->set_number("12345");
    phone->set_type(lm::helloworld_PhoneType_HOME);


    fstream output(file_path, ios::out | ios::trunc | ios::binary);

    if (!msg1.SerializeToOstream(&output)) {
        cerr << "Failed to write msg." << endl;
        return false;
    }
    return true;
}

void ListMsg(const lm::helloworld & msg) {
    cout << msg.id() << endl;
    cout << msg.str() << endl;
    for (int i =0; i<msg.phones_size(); i++)
    {

        cout << msg.phones(i).number() << endl;
    }
}


bool readBuf(string file_path)
{
    lm::helloworld msg1;
    {
        fstream input(file_path, ios::in | ios::binary);
        if (!msg1.ParseFromIstream(&input)) {
            cerr << "Failed to parse address book." << endl;
            return -1;
        }
    }
    ListMsg(msg1);
}

int main()
{
    string path = "./test_data.log";
    writeBuf(path);//消息初始化和存储传输
    readBuf(path);//消息读取与解析
    return 0;
}

会在同级目录下生成test_data.log

0x03 protobuf 还原

其中protobuf还原可使用protoc --decode_raw

protoc  --decode_raw <  /test_data.log
1: 100
2: "test"
4 {
  1: "12345678"
  2: 1
}

proto还原规则及更多细致数据解析:https://blog.csdn.net/yeyiqun/article/details/99310350

0x04 参考:

python版本:https://www.jianshu.com/p/b723053a86a6

你可能感兴趣的:(1,技术文章)