C++protobuf基础


简介

protobuf也叫protocol buffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python 等,每一种实现都包含了相应语言的编译器以及库文件。 由于它是一种二进制的格式,比使用 xml 、json进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。

安装

# 下载
wget https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protobuf-cpp-3.21.12.tar.gz 
# 解压
tar zxvf protobuf-cpp-3.21.12.tar.gz
# 进入到解压目录
cd protobuf-3.21.12/
# 构建并安装
./configure         # 检查安装环境, 生成 makefile
make                # 编译
sudo make install   # 安装
# sudo apt install libprotoc-dev # 安装依赖库(可选)
sudo ldconfig # ldconfig是一个动态链接库管理命令,其目的为了让动态链接库为系统所共享。
# 测试
protoc --version

libprotoc 3.21.12 # 显示版本号安装成功

创建测试项目

mkdir ProtoTest
cd ProtoTest
mkdir src test include
touch CMakeLists.txt  # 创建cmake文件,内容如下:
cmake_minimum_required(VERSION 3.10)

project(ProtoTest)

set(CMAKE_CXX_STANDARD 17)

# 设置bin目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 将src源文件目录下所有源文件名保存到SRC_LIST
aux_source_directory(src SRC_LIST)

# 将test源文件目录下所有源文件名保存到TEST_LIST
aux_source_directory(test TEST_LIST)

# 指定头文件目录
include_directories(include)

# 编译动态链接库
add_library(test  SHARED ${TEST_LIST})
target_link_libraries(test protobuf)
link_libraries(test)

# 将所有源文件编译成可执行文件
add_executable(ProtoTest ${SRC_LIST})

创建并执行proto文件

# touch test/Person.proto
syntax = "proto3";

message Address {
    int32 num = 1;
    bytes addr = 2;
}

message Person {
    int32 id = 1;
    repeated bytes name = 2;
    bytes sex = 3;
    int32 age = 4;
    Address addr = 5;
}

# 通过protoc命令生成 Person.pb.cc和Person.pb.h文件
# protoc -I test/ Person.proto  --cpp_out=test/
# 如果生成python文件则将参数改为 --python_out=
# 剪切Person.pb.h文件到include目录
# mv  test\Person.pb.h  include\

创建测试类

//
// Created by ZJ on 2023/11/21.
// include/mytest.h

#ifndef _MYTEST_H_
#define _MYTEST_H_

class MyTest {
 public:
  static void test ();
};

#endif//_MYTEST_H_


//
// Created by ZJ on 2023/11/21.
// test/mytest.cpp

#include "mytest.h"
#include "Person.pb.h"

void MyTest::test ()
{
  // 序列化
  Person p;
  p.set_id (1);
  // 添加数组元素
  p.add_name ();
  p.set_name (0, "zj");
  p.add_name ("zs");
  p.add_name ("ls");
  p.set_sex ("man");
  p.set_age (32);
  p.mutable_addr ()->set_addr ("山西运城");
  p.mutable_addr ()->set_num (310);

  // 序列化p对象,最终得到一个字符串
  std::string output;
  p.SerializeToString (&output);

  // 反序列化
  Person pp;
  pp.ParseFromString (output);
  std::cout << "id = " << pp.id ()
            << " ; age  = " << pp.age ()
            << " ; sex  = " << pp.sex ()
            << " ; addr = " << pp.addr ().addr ()
            << " ; num  = " << pp.addr ().num ()
            << std::endl;
  int size = pp.name_size ();
  for (int i = 0; i < size; ++i)
  {
    std::cout << pp.name (i) << std::endl;
  }
}

在主函数引入测试类

// src/main.c
#include "../include/mytest.h"
#include <iostream>

int main ()
{
  MyTest::test ();
  return 0;
}

编译项目

mkdir build
cd build
cmake .. -G "Unix Makefiles"
make

执行结果

bin/ProtoTest

id = 1 ; age  = 32 ; sex  = man ; addr = 山西运城 ; num  = 310
zj
zs
ls