protobuf使用(c++)

发布时间 2023-12-10 22:10:41作者: rainbowball

protobuf是什么

ptotobuf是谷歌的语言无关、平台无关可扩展的序列化结构数据格式,例如XML,但是更小、更快、更简单。你只需定义一次结构化数据,然后就可以使用特殊生成的源代码轻松地将结构化数据写入和读取到各种数据流,并且夸语言。

protobuf怎么用

版本及环境

protobuf版本:3.21.12 (3.22及之后版本需要依赖abseil-cpp)
环境:linux

安装

  1. 下载源码:https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protobuf-cpp-3.21.12.tar.gz
  2. 解压、编译、安装
    • tar zxvf protobuf-cpp-3.21.12.tar.gz
    • mkdir build; cd build; cmake .. -DCMAKE_INSTALL_PREIFX=/you/install/dir; make -j
    • make install

使用例子

  1. 目录结构:
examples/
├── CMakeLists.txt
├── protoc
│   └── example.proto
└── src
    └── example.cpp
  1. proto文件(具体可参考:Language Guide (proto 3))
syntax = "proto3"; // 声明使用的语法版本

package example; // 包名
// 消息结构定义,包含一个整数和一个字符串
message Msg {
    int32 id = 1;
    string name = 2;
}
  1. cmake文件
cmake_minimum_required(VERSION 3.16)
project(example)
set(CMAKE_CXX_STANDARD 11)

set(PROTOC_BIN /you/install/dir/bin/protoc)
set(PROTO_FILE_DIR /you/project/dir/examples/protoc)

add_custom_command(
  OUTPUT ${PROTO_FILE_DIR}/example.pb.h ${PROTO_FILE_DIR}/example.pb.cc
  COMMAND ${PROTOC_BIN} -I${PROTO_FILE_DIR} example.proto --cpp_out=${PROTO_FILE_DIR}
  DEPENDS ${PROTO_FILE_DIR}/example.proto
)

include_PROTO_FILE_DIRectories(~/tools/include/)
include_PROTO_FILE_DIRectories(~/tools/protobuf/examples/protoc/)
link_PROTO_FILE_DIRectories(~/tools/lib)

add_executable(example src/example.cpp ${PROTO_FILE_DIR}/example.pb.cc)
target_link_libraries(example protobuf)
  1. 源文件
#include "example.pb.h"

#include <cstdio>
#include <string>

void dump(std::string& data) {
  for (size_t i = 0; i < data.size(); i++) {
    printf("%02x ", data[i]);
  }
  printf("\n");
}
int main() {
  example::Msg msg;
  msg.set_id(1);
  msg.set_name("msg");
  std::string data;
  msg.SerializeToString(&data);
  dump(data);

  example::Msg msg1;
  msg1.ParseFromString(data);
  printf("id: %d; name: %s\n", msg1.id(), msg1.name().c_str());
  return 0;
}

输出如下:
08 01 12 03 6d 73 67
id: 1; name: msg

protobuf序列化说明

protobuf序列化是TLV格式即Tag-Length-Value

ID Name Used For
0 VARINT int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 I64 fixed64, sfixed64, double
2 LEN string, bytes, embedded messages, packed repeated fields
3 SGROUP group start (deprecated)
4 EGROUP group end (deprecated)
5 I32 fixed32, sfixed32, float

Tag = (field_number << 3) | wire_type
08 01 : 08 = (1 << 3) | 0; 01 = 1(id的值)
12 03 6d 73 67: 12 = (2 << 3) | 2; 03 = 3(msg长度); 6d 73 67 = msg(msg的ascii码)

如果深入了解可以搜索:Varint Zigzag 编解码


引用

Protocol Buffer官方文档