准备工作

protobuf官方文档

编译 Protobuf,需要安装工具:

brew install autoconf
brew install automake
brew install libtool

运行下面脚本进行编译:

./autogen.sh
./configure
make
make install

检查protobuf是否安装成功:

protoc --version

成功打印版本号则安装成功

libprotoc 3.21.12

Protobuf 支持的数据类型

Protobuf定义了一套基本数据类型

.proto Type Notes C Type
double double
float float
int32 使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代 int32
uint32 使用变长编码 uint32
uint64 使用变长编码 uint64
sint32 使用变长编码,这些编码在负值时比int32高效的多 int32
sint64 使用变长编码,有符号的整型值。编码时比通常的int64高效。 int64
fixed32 总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。 uint32
fixed64 总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。 uint64
sfixed32 总是4个字节 int32
sfixed64 总是8个字节 int64
bool bool
string 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。 string
bytes 可能包含任意顺序的字节数据。 string

protobuf 枚举类型

当需要定义一个消息类型的时候,可能想为一个字段指定“预定义值序列”中的一个值,这时候可以通过枚举实现。

syntax = "proto3";//指定版本信息,不指定会报错

//枚举消息类型,使用enum关键词定义,一个电话类型的枚举类型
enum PhoneType {
    MOBILE = 0; //proto3版本中,首成员必须为0,成员不应有相同的值
    HOME = 1;
    WORK = 2;
}

// 定义一个电话消息
message PhoneNumber {
    string number = 1; // 电话号码字段
    PhoneType type = 2; // 电话类型字段,电话类型使用PhoneType枚举类型
}

protobuf 数组类型

在protobuf消息中定义数组类型,是通过在字段前面增加repeated关键词实现,标记当前字段是一个数组。

  1. 整数数组的例子:

    message Msg {
    // 只要使用repeated标记类型定义,就表示数组类型。
    repeated int32 arrays = 1;
    }
    
  2. 字符串数组

    message Msg {
    repeated string names = 1;
    }
    

protobuf 消息嵌套

我们在各种语言开发中类的定义是可以互相嵌套的,也可以使用其他类作为自己的成员属性类型。

protobuf中同样支持消息嵌套,可以在一个消息中嵌套另外一个消息,字段类型可以是另外一个消息类型。

  • 引用其他消息类型的用法
// 定义Result消息
message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3; // 字符串数组类型
}
// 定义SearchResponse消息
message SearchResponse {
  // 引用上面定义的Result消息类型,作为results字段的类型
  repeated Result results = 1; // repeated关键词标记,说明results字段是一个数组
}
  • 消息嵌套

类似类嵌套一样,消息也可以嵌套。

例子:

message SearchResponse {
  // 嵌套消息定义
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
  }
  // 引用嵌套的消息定义
  repeated Result results = 1;
}
  • import导入其他proto文件定义的消息

我们在开发一个项目的时候通常有很多消息定义,都写在一个proto文件,不方便维护,通常会将消息定义写在不同的proto文件中,在需要的时候可以通过import导入其他proto文件定义的消息。

例子:

保存文件: result.proto

syntax = "proto3";
// Result消息定义
message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3; // 字符串数组类型
}

保存文件: search_response.proto

syntax = "proto3";
// 导入Result消息定义
import "result.proto";

// 定义SearchResponse消息
message SearchResponse {
  // 使用导入的Result消息
  repeated Result results = 1; 
}

protobuf map类型

protocol buffers支持字典类型定义。

  • map语法
map<key_type, value_type> map_field = N;

key_type可以是任何整数或字符串类型(除浮点类型和字节之外的任何标量类型)。请注意,枚举不是有效的key_type

value_type 可以是除另一个映射之外的任何类型。

  • map的例子
syntax = "proto3";
message Product {
    string name = 1; // 商品名
    // 定义一个k/v类型,key是string类型,value也是string类型
    map<string, string> attrs = 2; // 商品属性,键值对
}

Map 字段不能使用repeated关键字修饰。

定义消息

消息(message),在protobuf中指的就是我们要定义的数据结构

语法

syntax = "proto3";

message 消息名 {
    消息体
}

syntax关键词定义使用的是proto3语法版本,如果没有指定默认使用的是proto2

message关键词,标记开始定义一个消息,消息体,用于定义各种字段类型。

syntax = "proto3";

message Person {
  string name = 1;
  int32 age = 2;
  string tel = 3;
}

定义了一个Person消息,这个消息有3个字段,name和tel是字符串类型,age是int32类型。

我们通常将protobuf消息定义保存在.proto为后缀的文件中。

分配标识符

在消息定义中,每个字段后面都有一个唯一的数字,这个就是标识号。

这些标识号是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变,每个消息内唯一即可,不同的消息定义可以拥有相同的标识号。

保留标识号(Reserved) 如果你想保留一些标识号,留给以后用,可以使用下面语法:

message Person {
  reserved 2, 15, 9 to 11; // 保留2,15,9到11这些标识号
}

如果使用了这些保留的标识号,protocol buffer编译器会输出警告信息。

注释

往.proto文件添加注释,支持C/C++/java风格的双斜杠(//) 语法格式。

例子:

message Person {
  string name = 1;  //名字
  int32 age = 2;    //年龄
  string tel = 3;
}

为消息定义包

我们也可以为消息定义包。

proto协议文件编译为OC文件

protoc --proto_path=. --objc_out=.  Person.proto

参数的形式为: --参数命令名=参数

--proto_path=.​ 指出proto文件所在的根目录是哪里, 如果用​.​说明是当前目录

​--objc_out=.​ 指出 生成目录在哪里, 如果用​.​说明是当前目录

最后跟 proto文件的名称

iOS项目中使用

  • 使用cocoapods引入protobuf
pod ‘Protobuf’
  • 新建一个文件夹,拷贝已经有的.proto文件至此。用终端进入该文件夹,执行
protoc --plugin=/usr/local/bin/protoc-gen-objc *.proto --objc_out="./"
  • 文件夹下便可以看到xxx.pb.h和xxxx.pb.m这两个文件了。将生成的 .h 和 .m 文件添加到工程中,编译

序列化

我们在使用socket与服务器通信时,是以二进制数据流的形式进行传输的,因此我们要将Pbdata.pbobjc创建的对象转为二进制数据流,这个过程就称之为序列化

反序列化

服务器给我们传输的也是二进制数据流,所以我们需要不断拼接数据包,直到拼接成服务器规定的大小,将其转为OC对象,那么这个过程就是反序列化

results matching ""

    No results matching ""

    results matching ""

      No results matching ""