当前位置: 首页 > 工具软件 > Proto.Menu > 使用案例 >

proto学习

邴宏大
2023-12-01

介绍

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于通信协议、数据存储等。
protocol buffers的接口: c++, java, python
API doc link: https://developers.google.com/protocol-buffers/docs/reference/overview
参考:https://www.jianshu.com/p/a24c88c0526a
protobuf语法详解

通俗点说,就是将要发送的消息,通过protobuf格式发出去,自动进行封装。另一方对proto格式解析,直接得到原数据。

protocol buffers是什么?

是一种结构数据序列化方法, 可类比XML。
定义数据的结构 > 生成的源代码(.proto文件) -> 在数据流中&各种语言进行编写, 读取结构数据。

如何使用

  1. 定义.proto文件, 来定义你的数据结构;(消息格式文件)中定义 protocol buffer message 类型, 来指定你想如何对序列化信息进行结构化。 message 包含name-value对, 可嵌套。

缺省默认就设置为 optional

创建 .proto 文件,定义数据结构

message xxx {
  // 字段规则:required -> 字段只能也必须出现 1 次
  // 字段规则:optional -> 字段可出现 0 次或1次
  // 字段规则:repeated -> 字段可出现任意多次(包括 0)
  // 类型:int32、int64、sint32、sint64、string、32-bit ....
  // 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)
  字段规则 类型 名称 = 字段编号;
}

注:

1) message 定义中的每个字段都有唯一编号。
2) 单个 .proto 文件中定义多种 message 类型
3) message内可嵌套message
4) .proto 文件添加注释,可以使用 C/C++ 语法风格的注释 // 和 /* ... */ 
  1. 使用protoc编译器进行编译,导出c++代码。
    我们在 .proto 文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输。
    当需要把这些数据进行存储或传输时,就需要将这些结构数据进行序列化、反序列化以及读写。那么如何实现呢?不用担心,ProtoBuf 将会为我们提供相应的接口代码。如何提供?答案就是通过 protoc 这个编译器。

可通过如下命令生成相应的接口代码:

// $SRC_DIR: .proto 所在的源目录
// --cpp_out: 生成 c++ 代码
// $DST_DIR: 生成代码的目标目录
// xxx.proto: 要针对哪个 proto 文件生成接口代码

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto

当你在 .proto 上运行 protocol buffer 编译器时,编译器将会生成所需语言的代码,这些代码可以操作文件中描述的 message 类型,包括获取和设置字段值、将 message 序列化为输出流、以及从输入流中解析出 message。
对于 C++,编译器从每个 .proto 生成一个 .h 和 .cc 文件,其中包含文件中描述的每种 message 类型对应的类。
参考: https://www.jianshu.com/p/6f68fb2c7d19

  1. 使用c++的api进行数据的读写()。

person结构体举例:

message Person {
  required string name = 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];
  }

  repeated PhoneNumber phone = 4;
}

一个例子
创建.proto文件

message Example1 {
    optional string stringVal = 1;
    optional bytes bytesVal = 2;
    message EmbeddedMessage {
        int32 int32Val = 1;
        string stringVal = 2;
    }
    optional EmbeddedMessage embeddedExample1 = 3;
    repeated int32 repeatedInt32Val = 4;
    repeated string repeatedStringVal = 5;
}

调用生成接口, 进行序列化操作

#include <iostream>
#include <fstream>
#include <string>
#include "single_length_delimited_all.pb.h"

int main() {
    Example1 example1;
    example1.set_stringval("hello,world");
    example1.set_bytesval("are you ok?");

    Example1_EmbeddedMessage *embeddedExample2 = new Example1_EmbeddedMessage();

    embeddedExample2->set_int32val(1);
    embeddedExample2->set_stringval("embeddedInfo");
    example1.set_allocated_embeddedexample1(embeddedExample2);

    example1.add_repeatedint32val(2);
    example1.add_repeatedint32val(3);
    example1.add_repeatedstringval("repeated1");
    example1.add_repeatedstringval("repeated2");

    std::string filename = "single_length_delimited_all_example1_val_result";
    std::fstream output(filename, std::ios::out | std::ios::trunc | std::ios::binary);
    if (!example1.SerializeToOstream(&output)) {
        std::cerr << "Failed to write example1." << std::endl;
        exit(-1);
    }

    return 0;
}

.proto 模板
比如新建xxx.proto

syntax = "proto2";

package xxx.person;  # 该.proto产生的类会被封装在xxx::person命名空间中

import "yyy.proto";  # 引用其他的.proto

message student {

}

常见问题

  1. 出现 [libprotobuf WARNING google/protobuf/compiler/parser.cc:648] No syntax specified for the proto file: example.proto. Please use ‘syntax = “proto2”;’ or ‘syntax = “proto3”;’ to specify a syntax version. (Defaulted to proto2 syntax.)

解决:在开头写入: syntax = “proto2”;

 类似资料: