Protobuf 的基本使用

1 编译

  1. 准备编译环境
    1. CMake

    2. VS2017(当然 2017以下的版本都可以)

  2. 下载源码

    https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protobuf-all-3.6.1.zip

    或者去

    https://github.com/protocolbuffers/protobuf/releases 找到自己需要的版本,最好下载 protobuf-all-x.x.x 这个版本,代码比较全面

  1. 开始编译

    编译流程参考了官方的说明文档

    1. 启动VS的命令提示符

      x86 Native Tools Command Prompt for VS 2017

      或者

      x64 Native Tools Command Prompt for VS 2017

    2. 初始化环境

      C:\> cd C:\Path\to\protobuf
      C:\Path\to\protobuf> mkdir install
      C:\Path\to\protobuf> cd cmake
      C:\Path\to\protobuf\cmake> mkdir build & cd build
      C:\Path\to\protobuf\cmake\build> mkdir release & mkdir debug
              

    3. 配置 Release

      C:\Path\to\protobuf\cmake\build> cd release
      C:\Path\to\protobuf\cmake\build\release> cmake -G "NMake Makefiles" ^
      -DCMAKE_BUILD_TYPE=Release ^
      -DCMAKE_INSTALL_PREFIX=../../../install ^
      ../..
              

    4. 配置 Debug

      C:\Path\to\protobuf\cmake\build> cd debug
      C:\Path\to\protobuf\cmake\build\debug> cmake -G "NMake Makefiles" ^
      -DCMAKE_BUILD_TYPE=Debug^
      -DCMAKE_INSTALL_PREFIX=../../../install ^
      ../..
              

    5. 开始编译

      选择需要的版本 Debug or Release, 然后执行 nmake 即可

      C:\Path\to\protobuf\cmake\build> cd debug
      C:\Path\to\protobuf\cmake\build\debug> nmake
              

      等到编译完成后, 可以选择进行测试

      C:\Path\to\protobuf\cmake\build\debug> nmake check
              

      这个测试略久

    6. 安装

      C:\Path\to\protobuf\cmake\build\debug> nmake install
              

    7. 创建 sln 项目文件

      这个不一定需要, 如果想调试看看的话感觉可以生成

      C:\Path\to\protobuf\cmake\build> mkdir solution & cd solution
      cmake -G "Visual Studio 14 2015 Win64" ^
      -DCMAKE_INSTALL_PREFIX=../../../install ^
      ../..
              

      执行完成后, 会在 C:\Path\to\protobuf\cmake\build\solution 目录下生成 sln 项目文件

2. 文件结构说明

分为三个目录

.\include
.\lib
.\bin

当需要使用 protobuf 的时候, 在 VS 内添加 -IC:\Path\to\protobuf\install

并且将 .\lib 内的 .lib 文件放入 link 列表

bin 目录内的 protoc.exe 是用于编译 .proto 文件的

3. proto 语法

proto主要有2个版本的语法

具体可以参考官网

主要考虑 proto3 的语法, 3的语法比2更简单, 也更好编写

4. proto 例子

  1. C:\protobuf\example\mouse_event.proto
syntax = "proto3";

package example;

message mouse_move {
    int32 x = 1;
    int32 y = 2;
}

message mouse_wheel {
    int32 delta_x = 1;
    int32 delta_y = 2;
}
  1. C:\protobuf\example\unknown_event.proto
syntax = "proto3";

package unknownpackage;

message unknown {
    string text = 1;
}


  1. C:\protobuf\example\message.proto
syntax = "proto3";

import "mouse_event.proto";
import "unknown_event.proto";

package example;

enum message_type {
    MOUSE_MOVE = 0; // enum 的第一个值在 proto3 中必须以 0 开始
    MOUSE_WHEEL = 1;
}

message message{
    message_type type;

    mouse_move mouseMove;
    mouse_wheel mouseWheel;
    unknownpackage.unknown unknownValue;
}

5. 编译 proto

C:\protobuf\example> mkdir out
C:\protobuf\example> protoc.exe --cpp_out=.\out\ mouse_event.proto
C:\protobuf\example> protoc.exe --cpp_out=.\out\ unknown_event.proto
C:\protobuf\example> protoc.exe --cpp_out=.\out\ message.proto

如果没出错的话, 在路径 C:\protobuf\example\out\ 已经生成好了如下文件

  1. mouse_event_pb.h/mouse_event_pb.cpp

  2. unknown_event_pb.h/unknown_event_pb.cpp

  3. message_pb.h/message_pb.cpp

6. 使用

最基本的使用貌似比较简单

#include "mouse_event_pb.h"
#include "unknown_event_pb.h"
#include "message_pb.h"


int main(int argc, char **argv) {
    example::message msg;
    example::mouse_move *pMouseMove = new example::mouse_move();

    msg.set_type(example::message::MOUSE_MOVE);
    mouse_move->set_x(123);
    mouse_move->set_y(456);
    msg.set_allocated_mouseMove(pMouseMove);

    std::stringstream stream;
    msg.SerializeToOstream(&stream);
    auto data = stream.str();
    send(sock, data.data(), data.length(), 0);

    // 不需要 delete pMouseMove
    // 在 msg 析构的时候会自动释放

    // 读取值
    std::cout << mouse_move->x() << mouse_move->y() << std::endl;
    std::cout << msg.type() << msg.mouseMove().x() << std::endl;

    // 反序列化
    example::message msg2;
    msg2.ParseFromArray(data.data(), data.length());
    // 需要注意的是, protobuf 的数据中并不包括整体数据长度, 即如果通过网络传输则需要自行处理粘包的问题.


    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注