您的位置:

Proto协议详解

Protobuf(Protocol Buffers)是由Google公司开发的一套数据序列化协议,是一种轻便高效的结构化数据存储格式,可用于数据存储、通信协议等领域。

一、Proto协议简介

Proto协议是一种语言无关、平台无关、可扩展的数据序列化协议。

和XML、JSON等协议相比,Proto协议具有更高的效率,更小的消息体大小。相对于XML和JSON,Proto的解析速度大约快2~3倍,序列化后的消息体大小仅为JSON的1/3左右,XML的1/10左右。

Proto协议的优点在于其灵活性。在不更改协议的情况下,可以向现有消息添加新的属性,添加新的消息类型和子Message。

二、Proto协议的消息定义

Proto协议的消息定义基于.proto文件来描述消息。.proto文件是一个文本文件,包含了消息名、字段名、数据类型描述。

例如:

syntax = "proto3";
package my_package;
message Person {
  string name = 1;
  int32 age = 2;
  bool married = 3;
}

上述代码定义了一个名为Person的消息类型,包含了3个字段:name、age和married。其中各个字段的含义分别是:

  • name的类型是string,字段编号为1;
  • age的类型是int32,字段编号为2;
  • married的类型是bool,字段编号为3

三、Proto协议的数据类型

Proto协议支持的数据类型有基础数据类型、枚举类型和Message类型。

基础类型包括:

  • double
  • float
  • int32、int64、uint32、uint64、sint32、sint64、fixed32、fixed64、sfixed32、sfixed64
  • bool
  • string
  • bytes

枚举类型需要在.proto文件中单独声明,通过enum关键字指定,例如:

enum Color {
  RED = 0;
  BLUE = 1;
  GREEN = 2;
}

Message类型可以嵌套使用,例如一个Person对象中嵌套一个Address对象:

message Person {
  string name = 1;
  int32 age = 2;
  Address address = 3;
}
message Address {
  string street = 1;
  string city = 2;
  string state = 3;
  string zip_code = 4;
}

四、Proto协议的序列化和反序列化

Proto协议支持将消息体序列化为二进制数据流,以及将二进制数据流反序列化为消息体。

在序列化时,可以使用protobuf提供的SerializeToString()方法将消息序列化为字符串,也可以使用SerializeToOstream()方法将消息序列化为流。反序列化时,可以使用ParseFromString()方法将字符串解析为消息,也可以使用ParseFromIstream()方法将流解析为消息。

下面是序列化和反序列化的示例代码:

#include 
#include 
   
#include "example.pb.h"
using namespace std;
int main() {
  // 创建一个Person对象
  Person person;
  person.set_name("张三");
  person.set_age(20);
  person.set_married(false);
  Address *address = person.mutable_address();
  address->set_street("XX路");
  address->set_city("XX市");
  address->set_state("XX省");
  address->set_zip_code("000000");
  // 将Person对象序列化为字符串
  string str;
  person.SerializeToString(&str);
  cout << "序列化后的字符串:" << str << endl;
  // 将字符串反序列化为Person对象
  Person new_person;
  new_person.ParseFromString(str);
  cout << "反序列化后的Person对象:" << endl;
  cout << "name:" << new_person.name() << endl;
  cout << "age:" << new_person.age() << endl;
  cout << "married:" << new_person.married() << endl;
  Address new_address = new_person.address();
  cout << "address:" << endl;
  cout << "street:" << new_address.street() << endl;
  cout << "city:" << new_address.city() << endl;
  cout << "state:" << new_address.state() << endl;
  cout << "zip_code:" << new_address.zip_code() << endl;
  return 0;
}

   
  

五、Proto协议的使用场景

Proto协议通常用于网络通讯领域中的数据传输和RPC调用。在网络通讯中,使用Proto协议能够有效地降低消息的体积和网络开销,提高传输效率。

RPC调用是一种进程间通讯(IPC)的方式,Proto协议用于定义RPC调用的请求和响应消息格式,以及进行序列化和反序列化操作。

六、Proto协议的其他特点

Proto协议还具有以下几个特点:

  • 支持向前和向后兼容,即可以在不改变原有消息格式的情况下,添加或删除字段;
  • 支持多种语言进行消息定义及实现,包括C++、Java、Python等;
  • 具有较好的扩展性和可靠性,支持高并发情况下的数据传输。

七、结语

Proto协议是一种高效、可扩展、可靠的数据序列化协议,具有广泛的使用场景。熟练掌握Proto协议的使用,对于开发高可靠、高效的网络通讯和RPC调用应用具有重要的意义。