Protobuf介绍

目录

一、关于Protobuf

Protobuf的优势

二、Protobuf的使用步骤

三、Protobuf语法

1.文件声明

2.包名声明

3.消息体定义

4.数据类型

5.枚举类型

6.map类型

7.oneof

8.扩展

四、完整代码


一、关于Protobuf

Protocol Buffers(Protobuf)是一种由Google开发的高效、跨语言的数据序列化格式。

Protobuf使用.proto文件来定义数据结构,这些定义好的数据结构可以通过Protobuf编译器生成多种编程语言的代码,从而实现数据的序列化和反序列化。

    

Protobuf的优势

  • 更小的数据量:Protobuf的二进制编码通常比XML和JSON小3-10倍,因此在网络传输和存储数据时可以节省带宽和存储空间。
  • 更快的序列化和反序列化速度:由于Protobuf使用二进制格式,所以序列化和反序列化速度比XML和JSON快得多。
  • 跨语言:Protobuf支持多种编程语言,可以使用不同的编程语言来编写客户端和服务端,这种跨语言的特性使得Protobuf受到很多开发者的欢迎(JSON也是如此)。
  • 易于维护可扩展:Protobuf使用.proto文件定义数据模型和数据格式,这种文件比XML和JSON更容易阅读和维护,且可以在不破坏原有协议的基础上,轻松添加或删除字段,实现版本升级和兼容性。

      


   

二、Protobuf的使用步骤

  1. 确定数据格式:定义需要序列化的数据结构,可以是单一数据类型或复合数据类型。
  2. 创建.proto文件:根据Protobuf的语法,编辑.proto文件,定义消息类型和字段。
  3. 生成代码:使用Protobuf编译器(protoc)将.proto文件转化为相应编程语言的代码。
  4. 序列化和反序列化:在应用程序中使用生成的代码来进行数据的序列化和反序列化。

   


   

三、Protobuf语法

Protobuf 的语法主要包括以下几个部分:

1.文件声明

每个.proto文件通常以syntax指令开始,指明使用的Protobuf语法版本。

2.包名声明

使用package指令可以为.proto文件定义一个包名,有利于在不同项目或模块中管理Protobuf消息体。

3.消息体定义

消息体是Protobuf中的基本数据结构,使用message关键字定义。消息体可以包含多个字段,每个字段都有类型、名称和编号。

示例:

syntax = "proto3";
package mypb;

message Person {
    string name = 1;
    int32 age = 2;
    repeated bytes hobbies = 3;
}

4.数据类型

标量类型:double、float、int32、int64、uint32、uint64、sint32、sint64、fixed32、fixed64、sfixed32、sfixed64、bool、string、bytes

复合类型:enum、message、repeated(可重复字段)

5.枚举类型

Protobuf 中的枚举类型使用enum关键字定义,允许定义一组命名常量,proto3中枚举类型的第一个枚举值必须为0。

6.map类型

proto3支持map类型,用于表示键值对集合,map的键和值都可以是任意类型(除了另一个 map)。

7.oneof

oneof关键字用于在一个消息体中定义互斥字段,即在一个oneof块中,只能有一个字段被设置。

8.扩展

使用extend关键字可以在不改变原有消息体的情况下,向其中添加新的字段,有利于实现消息体的向后兼容性。

   


  

四、完整代码

#include
#include
#include"user.pb.h"

using namespace std;

void writeProtobuf() {
	mypb::User user;
	user.set_username("root");
	user.set_password("123456");
	user.set_private_ip("192.168.233.233");
	ofstream outFile("D://test.proto", ios::out | ios::trunc | ios::binary);
	user.SerializeToOstream(&outFile);
	outFile.close();
}

void readProtobuf() {
	mypb::User newUser;
	ifstream inFile("D://test.proto", ios::in | ios::binary);
	if (!inFile) {
		cerr << "inFile error" << endl;
		exit(1);
	}
	if (!newUser.ParseFromIstream(&inFile)) {
		cerr << "Parse error" << endl;
		exit(1);
	}
	cout << newUser.username() << endl;
	cout << newUser.password() << endl;
	cout << newUser.private_ip() << endl;
	inFile.close();
}


int main(void)
{
	writeProtobuf();
	readProtobuf();

	cout << endl;
	
	mypb::User user;
	user.set_username("root");
	user.set_password("root");
	user.set_private_ip("127.0.0.1");
	string data = user.SerializeAsString();

	mypb::User newUser;
	newUser.ParseFromString(data);
	cout << newUser.username() << endl;
	cout << newUser.password() << endl;
	cout << newUser.private_ip() << endl;


	return 0;
}

消息体:

syntax="proto3";

package mypb;

message User {
    string username = 1;
    string password = 2;
    string private_ip = 3;
}

   

参考文章:

vs使用protobuf的各种坑

  

你可能感兴趣的:(protobuf,c++)