protobuf序列化反序列化工具

一、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 取别名属于枚举选项

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值