在Unity中使用Protobuf(proto3)

版权声明:欢迎任何形式的转载,但请务必注明出处。由于鄙人水平有限,如果文章或代码有表述不当之处,还请不吝赐教。 https://blog.csdn.net/qq_36458268/article/details/81067280

有研究表明,一条消息数据,用protobuf序列化后的大小是json的10分之一,xml格式的20分之一,是二进制序列化的10分之一,ProtoBuf的优势还是很明显的。这里简单介绍哈使用

一、下载protobuf

https://github.com/google/protobuf/releases

选择protoc-3.6.0-win32.zip下载

二、编写proto原文件

syntax = "proto3";//标明proto版本

package protobuf;//包名

//一个message相当于一个类
//1,2,3不代表参数默认值,而是参数标签
//repeated 可以理解为数组

message StoreRequest {
  string name = 1;
  int32 num = 2;
  int32 result = 3;
  repeated string myList=4;
}

(1)版本号

对于一个pb文件而言,文件首个非空、非注释的行必须注明pb的版本,即syntax = "proto3";,否则默认版本是proto2。

(2)Message

一个message类型看上去很像一个Java class,由多个字段组成。每一个字段都由类型、名称组成,位于等号右边的值不是字段默认值,而是数字标签,可以理解为字段身份的标识符,类似于数据库中的主键,不可重复,标识符用于在编译后的二进制消息格式中对字段进行识别,一旦你的pb消息投入使用,字段的标识就不应该再改变。数字标签的范围是[1, 536870911],其中19000~19999是保留数字。

(3)类型

每个字段的类型(int32,string)都是scalar的类型,和其他语言类型的对比如下:

扫描二维码关注公众号,回复: 2898966 查看本文章

(4)修饰符

如果一个字段被repeated修饰,则表示它 是一个列表类型的字段,比如上面

 repeated string myList=3; 

等于是List<string> myList

如果你希望可以预留一些数字标签或者字段可以使用reserved修饰符:

message Login {
  reserved 2, 15, 9 to 11;
  reserved "lg", "bo";
  string bo = 3; // 编译报错,因为‘bo’已经被标为保留字段
}

(5)默认值

  1. string类型的默认值是空字符串
  2. bytes类型的默认值是空字节
  3. bool类型的默认值是false
  4. 数字类型的默认值是0
  5. enum类型的默认值是第一个定义的枚举值
  6. message类型(对象,如上文的SearchRequest就是message类型)的默认值与语言相关
  7. repeated修饰的字段默认值是空列表

注:如果一个字段的值等于默认值(如bool类型的字段设为false),那么它将不会被序列化,这样的设计是为了节省流量

(6)枚举

每个枚举值有对应的数值,数值不一定是连续的。第一个枚举值的数值必须是0且至少有一个枚举值,否则编译报错。编译后编译器会为你生成对应语言的枚举类。

message StoreRequest {
  string name = 1;
  int32 number = 2;
  int32 result = 3;
enum CoinType
{
    None=0;
    CT_cny = 1;
    CT_usd = 2;
    CT_hkd = 3;
    CT_jpy = 4;
    CT_eur = 5;
}
  CoinType coin = 4;
}

可以使用MessageType.EnumType的形式引用定义在其它message类型中的枚举。

注:由于编码原因,出于效率考虑,官方不推荐使用负数作为枚举值的数值。

(7)Maps

pb中也可以使用map类型(官方并不认为是一种类型,此处称之为类型仅便于理解),绝大多数scalar类型都可以作为key,除了浮点型和bytes,枚举型也不能作为key,value可以是除了map以外的任意类型:

map<string, object> obj = 3;

map其实是一种语法糖,它等价于以下形式:

message MapField {
  key_type key = 1;
  value_type value = 2;
}

repeated MapField map_field = N;

注:map类型字段不支持repeated,value的顺序是不定的。

(8)包

你可以用指定package以避免类型命名冲突:

package store.ba;
message Buy{...}

然后可以用类型的全限定名来引用它:

message Store{
...
store.ba.Buy buy=1;
..
}

指定包名后,会对生成的代码产生影响,生成的类会以你指定的package作为包名。

这里不再做详细介绍,可以参照https://developers.google.com/protocol-buffers/docs/encoding?hl=zh-cn

三、配置环境变量

将解压出来的protoc.exe放在一全英文路径下,并把其路径名放在windows环境变量下的path下。

(1)以win7为例,右键我的电脑->属性->高级系统设置->环境变量->系统变量->双击修改 变量”path” ,添加protoc.exe的路径,即:

;E:\protoc-3.6.0-win32\bin

(2)打开cmd 执行

protoc --version

显示libprotoc  3.6.0即配置完毕

四、win+R打开cmd窗口执行以下命令

E:\protoc-3.6.0-win32\bin\protoc.exe -I=e:\protoc-3.6.0-win32\bin   --csharp_out=e:\protoc-3.6.0-win32\bin    e:\protoc-3.6.0-win32\bin\msg.proto
 

若配置了环境变量:

protoc -I=e:\protoc-3.6.0-win32\bin     --csharp_out=e:\protoc-3.6.0-win32\bin     e:\protoc-3.6.0-win32\bin\msg.proto
 

protoc -I=源地址     --csharp_out=目标地址      源地址/xxx.proto

五、然后就看到目标路径生成了Msg.cs

(未完待续)

猜你喜欢

转载自blog.csdn.net/qq_36458268/article/details/81067280