一、protobuf 的基本使用
1.首行是语法指定行,syntax
2.定义命名空间,package
3.创建message对象,给属性字段赋予编号
4.编译,protoc --cpp_out=(生成目标位置) (依赖文件) eg:protoc --cpp_out=. contacts.proto
5.protoc -I(大写i)(去哪一个目录下搜索依赖文件) --cpp_out=(生成目标位置) (依赖文件)
6.序列化的结果是一个二进制文件
7.g++ -o TestPb main.cc contacts.pb.cc -std=c++11 -lprotobuf
//字段编号的范围一般是1~2^29-1,其中19000-19999不可用
//若值为负数则用sint32,因为变长编码从4到了10,uint使用变长编码,fixed32定长4字节,值大于2^28用fixed
//长度不能超过2 ^ 32 , 任意字节序列,长度不能超过2^32
//1-15字段是1个字节,16-2047是2个;1-15标记频繁出现的字段
二、proto3语法
特殊类型有4个。
1.字段规则
(1)singular(字段默认使用规则),最多使用一个字段,有多个以最后一个为主;
(2)repeated string 构建数组类似vector;
2.message对象
syntax = "proto3";
package contacts2;
import "google/protobuf/any.proto";
// import "phone.proto";
// message PeopleInfo {
// string name = 1;
// int32 age = 2;
// repeated phone.Phone phone = 3;
// }
message Address {
string home_address=1;//家庭住址
string unit_address=2;//单位地址
}
message PeopleInfo {
string name = 1;
int32 age = 2;
message Phone {
string number = 1;
enum PhoneType{
MP = 0;//移动电话
TEL = 1 ;//固定电话
}
PhoneType type = 2;
}
repeated Phone phone = 3;
google.protobuf.Any data = 4;
oneof other_contact{
string qq = 5;
string wechat = 6;
}
map<string, string> remark = 7;
}
message Contacts {
repeated PeopleInfo contacts = 1;
}
1.支持嵌套定义message,并且字段标识可以重新从1开始使用,生成的文件是用下划线分割基类和派生类的方式来命名,嵌套定义生成的类如:PeopleInfo_Phone;
2.使用hexdump指令将二进制转换为ASCII值或8 10 16 进制的格式;-C 16进制和规范的ASCII码;
3.get函数是name(),set函数是set_name(),序列化SerializeTo*(),反序列化ParseFrom,数组类型则是用contacts(i)来访问第几个,添加是add_contacts();
3.查看所有的protoc选项 protoc -h
protoc --decode=contacts2.Contacts contacts.proto 0<contacts.bin
如:=命名空间.类 依赖文件 因为是从标准输入读取所以重定向到标准输入
查看生成的二进制文件的内容,会将utf-8格式的汉字转换成8进制格式
4.枚举常量
1.枚举常量定义一般大写,并且0值常量必须存在而且得是第一个常量的值;
2.枚举常量值要在32位整数范围内并且不建议设置负值;
3.枚举类型可以嵌套定义在message里
4.同级的枚举类型变量名不可以一样
5.枚举类型0是默认值
5.Any类型
Any类型,存放任意message类型,先用people.mutable()开辟空间,在用people.data().packfrom(address)来转变成Any类型,Unpack()转变成Address类型。
6.oneof类型
备注信息多选一,
oneof
{
string qq;
string wechat;
}
1.虽然使用了{}但是{}里的内容其实是和外界同级的,字段标识不能从0开始;
2.oneof类型{}里面的内容不能用repeated修饰;
3.设置了多个只会保留最后一次设置的成员;
4.people.other_contact_case(); // 直接将oneof类型转换位枚举类型,存放在OtherContactCase;
7.map类型
1.keytype 除了float和bytes的所有标量类型,valuetype支持所有类型;
不支持repeated修饰,map是无序的;
8.默认值
1.对于字符串,默认值为空字符串;
2.对于字节,默认值为空字节;
3.对于布尔值,默认值为false;
4.对于数值类型,默认值为0(float 0.0);
5.对于枚举,默认值是第一个定义的枚举值,必须为0;
6.对于消息字段,未设置该字段,它的取值是依赖于语言;
7.对于设置了repeated的字段的默认值是空的(通常是相应语言的一个空列表);
8.对于消息字段、oneof字段和any字段,C++和Java语言中都有has_方法来检测当前字段是否被设置;
9.proto3语法中,对于标量数据类型是没有has_方法的,无法检测成员内容是反序列化出来的,还是设置的默认值;
9.更新消息
1.新增字段不要和老字段冲突;
2.修改字段的时候禁止修改任何已有字段的字段编号;
3.int32 uint32 int64 uin64和bool是完全兼容的 ;
4.sint32和sint64相互兼容但不与其他的整型兼容;
5.string 和 bytes在合法UTF-8字节前提下也是兼容的;
6.bytes包含消息编码版本的情况下,嵌套消息与bytes也是兼容的;
7.fixed32与sfixed32兼容,fixed64与sfixed64兼容;
8.enum 与int32,uint32,int64和uint64兼容(注意若值不匹配会被截断)。但要注意当反序列化消息时会根据语言采用不同的处理方案:
例如,未识别的proto3枚举类型会被保存在消息中,但是当消息反序列化时如何表示是依赖于编程语言的。整型字段总是会保持其的值。
9.oneof:
将一个单独的值更改为新oneof类型成员之一是安全和二进制兼容的。
若确定没有代码一次性设置多个值那么将多个字段移入一个新oneof类型也是可行的。将任何字段移入已存在的oneof类型是不安全的。将任何字段移入已存在的oneof类型是不安全的。删除老字段,要保证不使用已经被删除的或者已经被注释的字段编号,否则另一个proto文件使用了相同字段编号就会使得数据被破坏。
10.被注释或者删除的字段编号要用reserved修饰,其他字段使用被修饰的字段编号时就会报错,可以使用100 to 200来保留字段编号,被保留后,读出来的字段的值就是默认值;
9.1.未知字段
在3.5版本之前时是会直接丢弃的。server设置的birthday字段,client未设置时,client读取到不认识的字段会放到未知字段里来进行保存,用client进行序列化时,也会将未知字段保存在序列化的结果中。
自定义消息继承自message,继承自message_lite(提供了序列化与反序列化),message使用了reflection,和descriptor
//unknownfield use unknownfieldset use reflection
//而未知字段需要使用unknownfield类来获取
//message使用了getreflection(),getdescriptor()来获取相关的两个类,静态方法
//descriptor提供了描述message定义的相关内容
//reflection提供了message读写字段的一些方法
//getunknownfields()获取unknownfieldset里的内容(一批字段),里面的字段就是unknownfield,
//遍历set拿到未知字段
9.2前后兼容性
向前兼容,老模块能够识别新模块,向后兼容,新模块能够识别老模块
10.选项功能
1.所有的选项存放在/google/protobuf/descriptor.proto中
//option关键字可以影响编译器的某些处理方式
message Fileoptions { ... }
//文件选项定义在Fileoptions消息中
message MessageOptions { ... }
/消息类型选项定义在MessageOptions消息中
message Fieldbptions { ... }
//消息字段选项定义在FieldOptions消息中
message Oneof0ptions { ... }
l /oneof字段选项定义在Oneof0ptions消息中
message Enumoptions { ... }
//枚举类型选项定义在EnumOptions消息中
message EnumValueOptions { ..}
//枚举值选项定义在 EnumValueOptions消息中
手机用户1456jprya
message ServiceOptions { ...}
//服务选项定义在 Serviceoptions、消息中
message MethodOptions { ... }
//服务方法选项定义在MethodOptions消息中
10.1常用选项
1.optimise_for 优化属于文件选项
2.allow_alias 取别名属于枚举选项