简介

上一篇文章我们对google的protobuf已经有了一个基本的认识,并且能够使用相应的工具生成对应的代码了。但是对于.proto文件的格式和具体支持的类型还不是很清楚。今天本文将会带大家一探究竟。

注意,本文介绍的协议是proto3版本的。

定义一个消息

protobuf中的主体被称为是message,可以将其看做是我们在程序中定义的类。我们可以在.proto文件中定义这个message对象,并且为其添加属性,如下所示:

syntax = "proto3";

message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}

上例的第一行指定了.proto文件的协议类型,这里使用的是proto3,也是最新版的协议,如果不指定,默认情况下是proto2。

类型定义

这里我们为SearchRequest对象,定义了三个属性,其类型分别是String和int32。

String和int32都是简单类型,protobuf支持的简单类型如下:

protobuf类型 说明 对应的java类型
double 双精度浮点类型 double
float 浮点类型 float
int32 整型数字,最好不表示负数 int
int64 整型数字,最好不表示负数 long
uint32 无符号整数 int
uint64 无符号整数 long
sint32 带符号整数 int
sint64 带符号整数 long
fixed32 四个字节的整数 int
fixed64 8个字节的整数 long
sfixed32 4个字节的带符号整数 int
sfixed64 8个字节的带符号整数 long
bool 布尔类型 boolean
string 字符串 String
bytes 字节 ByteString

当然protobuf还支持复杂的组合类型和枚举类型。

枚举类型在protobuf中用enum来表示,我们来看一个枚举类型的定义:

message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
}

上面我们定义了一个枚举类型Corpus,枚举类型中定义的枚举值是从0开始的,0也是枚举类型的默认值。

在枚举中,还可以定义具有相同value的枚举类型,但是这样需要加上allow_alias=true的选项,如下所示:

message MyMessage1 {
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
}
message MyMessage2 {
enum EnumNotAllowingAlias {
UNKNOWN = 0;
STARTED = 1;
// RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside.
}
}

在枚举类型中,如果我们后续对某些枚举类型进行了删除,那么被删除的值可能会被后续的用户使用,这样就会造成潜在的代码隐患,为了解决这个问题,枚举提供了一个reserved的关键词,被这个关键词声明的枚举类型,就不会被后续使用,如下所示:

enum Foo {
reserved 2, 15, 9 to 11, 40 to max;
reserved "FOO", "BAR";
}

reserved关键字也可以用在message的字段中,表示后续不要使用到这些字段,如下:

message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}

字段的值

我们可以看到,每个message的字段都分配了一个值,每个字段的值在message中都是唯一的,这些值是用来定位在二进制消息格式中的字段位置。所以一旦定义之后,不要随意修改。

要注意的是值1-15在二进制中使用的1个字节来表示的,值16-2047需要使用2个字节来表示,所以通常将1-15使用在最常见的字段和可能重复的字段,这样可以节约编码后的空间。

最小的值是1,最大的值是2的29次方-1,或者536,870,911。这中间从19000-19999是保留数字,不能使用。

当消息被编译之后,各个字段将会被转成为对应的类型,并且各个字段类型将会被赋予不同的初始值。

strings的默认值是空字符串,bytes的默认值是空bytes,bools的默认值是false,数字类型的默认值是0,枚举类型的默认值是枚举的第一个元素。

字段描述符

每个消息的字段都可以有两种描述符,第一种叫做singular,表示message中可以有0个或者1个这个字段,这是proto3中默认的定义方式。

第二种叫做repeated,表示这个字段在message中是可以重复的,也就是说它代表的是一个集合。

添加注释

在proto中的注释和C++的风格类似,可以使用: // 或者 /* ... */ 的风格来注释,如下所示:

/* 这是一个注释. */

message SearchRequest {
string query = 1;
int32 page_number = 2; // 页面的number
int32 result_per_page = 3; // 每页的结果
}

嵌套类型

在一个message中还可以嵌入一个message,如下所示:

message SearchResponse {
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated Result results = 1;
}

在上例中,我们在SearchResponse定义了一个Result类型,在java中,实际上可以将其看做是嵌套类。

如果希望在message的定义类之外使用这个内部的message,则可以通过_Parent_._Type_来定义:

message SomeOtherMessage {
SearchResponse.Result result = 1;
}

嵌套类型可以任意嵌套,如下所示:

message Outer {                  // Level 0
message MiddleAA { // Level 1
message Inner { // Level 2
int64 ival = 1;
bool booly = 2;
}
}
message MiddleBB { // Level 1
message Inner { // Level 2
int32 ival = 1;
bool booly = 2;
}
}
}

Map

如果想要在proto中定义map,可以这样写:

map<key_type, value_type> map_field = N;

这里的value_type可以是除map之外的任意类型。注意map不能是repeated。

map中的数据的顺序是不定的,我们不能依赖存入的map顺序来判断其取出的顺序。

总结

以上就是proto3中定义声明文件该注意的事项了,大家在使用protobuf的时候要多加注意。

本文已收录于 http://www.flydean.com/02-protocolbuf-detail/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

protocol buffer没那么难,不信你看这篇的更多相关文章

  1. Google Protocol Buffer 简单介绍

    以下内容主要整理自官方文档. 为什么使用 Protocol Buffers .proto文件 Protocol Buffers 语法 编译.proto文件 Protocol Buffers API 枚 ...

  2. 快来看看Google出品的Protocol Buffer,别仅仅会用Json和XML了

    前言 习惯用 Json.XML 数据存储格式的你们,相信大多都没听过Protocol Buffer Protocol Buffer 事实上 是 Google出品的一种轻量 & 高效的结构化数据 ...

  3. Protocol Buffer技术详解(数据编码)

    Protocol Buffer技术详解(数据编码) 之前已经发了三篇有关Protocol Buffer的技术博客,其中第一篇介绍了Protocol Buffer的语言规范,而后两篇则分别基于C++和J ...

  4. google protocol buffer -2-.proto 定义规则

    essage为主要关键字,类似于java中的class.定义简单message类型 SearchRequest.proto定义了每个查询请求的消息格式,每个请求都会有查询关键词query,查询结果的页 ...

  5. php实现把数组排成最小的数(核心是排序)(看别人的代码其实也没那么难)(把php代码也看一下)(implode("",$numbers);)(usort)

    php实现把数组排成最小的数(核心是排序)(看别人的代码其实也没那么难)(把php代码也看一下)(implode("",$numbers);)(usort) 一.总结 核心是排序 ...

  6. 从零开始山寨Caffe·伍:Protocol Buffer简易指南

    你为Class外访问private对象而苦恼嘛?你为设计序列化格式而头疼嘛? ——欢迎体验Google Protocol Buffer 面向对象之封装性 历史遗留问题 面向对象中最矛盾的一个特性,就是 ...

  7. Google Protocol Buffer的安装与.proto文件的定义

    什么是protocol Buffer呢? Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准. 我理解的就是:它是一种轻便高效的结构 ...

  8. Corba、protocol buffer、SOA的区别 (转)

    From: http://www.zhihu.com/question/20279489 Google的protocol buffers?这个跟corba.soa没啥关系,不同层次的概念,没法比.pr ...

  9. protocol buffer和当年corba ,和现在SOA有啥异同点

    CORBA是对象管理集团(OMG)的一个标准,使得不同语言编写的,运行在不同计算机上的能够协同工作.标准包括分布式计算的通讯协议(GIOP和IIOP),可映射到多种语言的接口描述语言(IDL),对象请 ...

  10. Google的Protocol Buffer格式分析

    [转]转自:序列化笔记之一:Google的Protocol Buffer格式分析 从公开介绍来看,ProtocolBuffer(PB)是google 的一种数据交换的格式,它独立于语言,独立于平台.作 ...

随机推荐

  1. 项目实战:Qt多段Y轴折线图框架(双Y轴段折线、支持拽拖、浮动游标显示X值各段Y值、支持大量实时显示下位机数据)

    若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/111660400长期持续带来更多项目与技术分享, ...

  2. Kotlin 协程二 —— 通道 Channel

    目录 一. Channel 基本使用 1.1 Channel 的概念 1.2 Channel 的简单使用 1.3 Channel 的迭代 1.4 close 关闭 Channel 1.5 Channe ...

  3. 【Azure 应用程序见解】通过Azure Funciton的门户启用Application Insights后,Application Insights无法收到监控数据

    问题描述 比较早期创建的Azure Funciton服务,近期发现在门户中已经启用了Application Insights功能,但是正确配置Applicaiton Insights后,却无法获取关联 ...

  4. Hugo 建站经验之谈

    前言 建站工具,早已不是一个新颖的话题,抛开可视化建站单论开发层面,各类语言都有推出广受欢迎的建站框架,比如 Python 开发的 Pelican,JavaScript 开发的 Hexo,以及市场份额 ...

  5. centos 7与8修改主机名的各种方法

    hostname 查看当前系统主机名,知道当前主机名为localhost 当然在centos7特地添加了hostnamectl命令查看,修改主机名 使用hostnamectl set-hostname ...

  6. 【MongoDB详细步骤】(内附源码)

    第01章-MongoDB 1.安装和启动(docker方式) 1.1.拉取镜像 docker pull mongo:4.4.8 1.2.创建和启动容器 docker run -d --restart= ...

  7. 摆脱鼠标系列 Trigger Suggest 快捷键 改成 Shift + Space

    摆脱鼠标系列 Trigger Suggest 快捷键 改成 Shift + Space 看marp插件的时候,发现用ctrl + space 自动提示,但是我这里是输入法

  8. getUserMedia 获取 摄像头 拍照 代码 1920-1080 video canvas

    getUserMedia 获取 摄像头 拍照 代码 1920-1080 video canvas 20210422 摄像头代码 是基于 https 协议的,需要开启协议后才能测试 http-serve ...

  9. SecureCRT windows 登录 linux

    SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录UNIX或Linux服务器主机的软件.SecureCRT支持SSH,同时支持Telnet和rlog ...

  10. 生成文件名为系统时间的C源码实例

    一 最近遇到了一个需要根据时间记录文件名的.先写一个实例来实战: #include<stdlib.h> #include<time.h> #include<stdio.h ...