文档章节

gRPC proto3语法指南

zhangzhihai
 zhangzhihai
发布于 2017/01/10 10:19
字数 1805
阅读 1375
收藏 0

 

读完protobuf一些文档,写点东西,权作记忆。

https://github.com/google/protobuf/blob/master/CHANGES.txt

google发布了protobuf v3,为了pb更好用,更跨语言,他对protobuf v2做了以下change:

      1. Removal of field presence logic for primitive value fields(匪夷所思,留存以待以后翻译出来), 删除required(大大地赞同,即保留repeated,required和optional都不要了,默认就是optional),删除默认值(不明白)。谷歌生成这些改变视为了更好的兼容Android Java、Objective C和Go语言;

      2. 删除对unknown field的支持;

      3. 不再支持继承,以Any type代之;

      4 修正了enum中的unknown类型;

      5 支持map;

         protobuf v2和v3都支持map了,其声明形式如下: 

         message Foo {

                map<string, string> values = 1;

         }

         注意,此处的map是unordered_map。

      6 添加了一些类型集,以支持表述时间、动态数据等;

      7 默认以json形式代替二进制进行编码。

目前v3 alpha版仅仅实现了1-5这五个feature,6和7还未支持。新添加了syntax关键字,以指明proto文件的protobuf协议版本,不指明则是v2。如:

 // foo.proto

      syntax = "proto3";

      message Bar {...}

如果你目前使用了v2,那么暂时不支持你切换到v3,我们还会对v2提供支持。如果你是新手,那就大胆使用v3吧。

 

 

https://github.com/golang/protobuf

1 go的protobuf实现不支持RPC。

2 go的protobuf实现了一个go的插件protoc-gen-go,他放置的地方必须在$GOBIN里面,默认放在$GOPATH/bin。它也必须在$PATH里面,以让protoc编译器找到。protoc把proto文件编译成go的源码文件,其名称后缀是.pb.go,protoc命令格式如下:

protoc --go_out=plugins=grpc:. *.proto

3 .pb.go源码的一些事项如下:

  - 变量名称采用骆驼命名法,如camel_case被编译为CamelCase.

  - 不会为field生成set方法,直接为成员赋值即可。 

  - 没有setter,但是有getter方法,如果field被设置了值,则返回设置的值。如果没有设置,则返回默认值。如果连message都没有收到,就返回nil。

  - struct的所有成员初始值都是零值,如果要给其成员赋值,就必须在序列化之前。序列化后再修改struct的成员值,没有任何意义。

  - struc的 Reset()会将struct的所有field的值清零。

  - 非repeated的field成员的类型都是指针类型,当它为空时,意味着其值为空。如"required field int32 f "或者"optional field int32 f "被编译后的类型都是F *int32。

  - Repeated类型的fields被编译后则是slices.

  - 与其他语言一样,go会生成Helper函数,以便于设置field的值。针对获取值得Helper函数不再建议使用。                        msg.Foo = proto.String("hello") // set field

  - 一个field如果有default值,则这个值会被编译为一个常量,其名称的规则为Default_StructName_FieldName,而且相关的Get方法会默认返回这个值。不见直接用这些const值。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

message Test {

    optional int32 type = 2 [default=77];

    extensions 100 to 199;

}

 

type Test struct {

    Type             *int32                    `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`

}

 

 

const Default_Test_Type int32 = 77

     

func (m *Test) GetType() int32 {

    if m != nil && m.Type != nil {

        return *m.Type

    }

    return Default_Test_Type

}

 

  -  Enum类型会对类型名称和其值分别处理,其值的Enum名称以类型做前缀,每个field的名称和值会形成map,可以互相查找。

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

enum FOO {

    X = 17; 

    Y = 18; 

};

==>

type FOO int32

 

const (

    FOO_X FOO = 17

    FOO_Y FOO = 18

)

 

var FOO_name = map[int32]string{

    17: "X",

    18: "Y",

}

var FOO_value = map[string]int32{

    "X": 17, 

    "Y": 18, 

}

 

func (x FOO) Enum() *FOO {

    p := new(FOO)

    *p = x 

    return p

}

func (x FOO) String() string {

    return proto.EnumName(FOO_name, int32(x))

}

func (x *FOO) UnmarshalJSON(data []byte) error {

    value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")

    if err != nil {

        return err

    }

    *x = FOO(value)

    return nil

}

  - 如果group和enum是内置在message中的,则其名称的前缀会有message的名称。 

  - Extensions会被编译为一个变量,其名称开头为E_。extension相关的方法有 HasExtension, ClearExtension, GetExtension, SetExtension .

  - 序列化方法有Marshal和Unmarshal.

 

 

 

 

https://developers.google.com/protocol-buffers/docs/proto:

1 default value。bool的默认值是false,数值的默认值是0,enum的默认值是其第一个元素,string的默认值是空字符串。

 2 tag id. id 1-15占用1个字节,16到2047占用两个字节。所以1-15要留个频繁使用的字段,不要刚开始定义字段的是时候都分配出去。

   tag值最小是1, 最大是(2^29 - 1)即536,870,911,但是要避开19000到19999,这是protobuf内置的类型要用到的tag id。 

 3 enum可以有alias。enum的值不能为负数。

 enum EnumAllowingAlias {

  option allow_alias = true;

  UNKNOWN = 0;

  STARTED = 1;

  RUNNING = 1;

}

enum EnumNotAllowingAlias {

  UNKNOWN = 0;

  STARTED = 1;

  // RUNNING = 1;  // Uncommenting this line will cause a compile error inside Google and a warning message outside.

}

 4 当协议更新的时候,如果某个字段过时了,就可以更改field的name,如"OBSOLETE_xxx",以告诉使用者不要在使用这个field。

   也可以更改field type,前提是tag id不变,这些类型就是兼容的(之所以能兼容,按照我的理解,一个field就是一个kay-value对,tag id为key,value即为值,而type只是在序列化和反序列化的时候起到解释值的作用,并无其他作用;key = (tag << 3) | wire_type,即类型占用最多3个字节,所以有上面的tag范围是2^29 - 1)。如下几个类型是兼容的:

   A int32 uint32 int64 uint64 bool    

   B sint32 siint64

   C string bytes (字符类型是UTF8)

   D fixed32 sfixed32 fixed64 sfixed64

   E optional repeated

   F default([default = value])value也可以被修改

 5 protoc --proto-path= --cpp_out= --java_out= file.proto

   --proto-path可以被-I代替。

 6 protobuf对repeated压缩不够好,所以尽量在后面加上[packed = true]。

 7 序列化的时候不能把多个message序列化后的内容放在一起发出去,尽量以len1 + msg1 + len2 + msg2这种形式发送。

 8 不要让protobuf对象成为全局变量或者类成员,因为其clear方法只会把占用的内存空间清零,而不会释放,使得进程空间越来越大,可参考《Protobuf使用不当导致的程序内存上涨问题》。 

 

 

https://developers.google.com/protocol-buffers/docs/encoding:

1 正常field的kv对的编码顺序是:1 小端序;2 varints,即每7个bit为一个byte,在byte的第一个bit赋值1,最后一个byte的第一个bit赋值0;3 对field的tag加type构成key,值为value,即((tag_id << 3) | wire_type) + value。但是针对repeated这种,其结果为((tag_id << 3) | wire_type) + len + value,长度len为array size,prootbuf解析度时候,会根据wire_type为2知道这是个array。

 

2 如果序列化的时候,多个kv对用了一个tag id,则这个kv对应的field的值为最后一次出现的kv对的值。

3 repeated的[packed = true]只有type为数值的时候才能用。

 

https://github.com/google/protobuf/tree/v3.0.0-alpha-1

1 安装步骤:

  

$ ./configure --prefix=/home/user/bin/
$ make
$ make check
$ make install

 

2 如果不想生成动态protobuf库,则用命令./configure --disable-shared。

repeated类型相当于std的vector,可以用来存放N个相同类型的内容

参考

https://github.com/google/protobuf/blob/master/examples/addressbook.proto

本文转载自:http://blog.csdn.net/menggucaoyuan/article/details/43602915

zhangzhihai
粉丝 2
博文 18
码字总数 2207
作品 0
浦东
高级程序员
私信 提问
grpc| python 实战 grpc

date: 2018-5-15 22:12:32 title: grpc| python 实战 grpc description: 只要代码可以跑起来, 很多难题都会迎刃而解. so, keep coding and stay hungry. 之前用 swoole 写 server 时就接触过...

daydaygo
2018/05/16
0
0
springboot整合gprc 传输对象

一,grpc简介: GRPC是google开源的一个高性能、跨语言的RPC框架,基于HTTP2协议,基于protobuf 3.x,基于Netty 4.x +。GRPC与thrift、avro-rpc等其实在总体原理上并没有太大的区别,简而言之...

xiaomin0322
2018/04/26
734
0
gRPC基本使用(一)--java与go之间的相互调用

gRPC是一个高性能、开源、通用的RPC框架,面向移动和HTTP/2设计。gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制。 Protocol Buffers 是一种轻便高效的结...

明天以后
2018/11/24
677
0
grpc+protobuf 的C++ service 实例解析

这篇文章将会简单的描述一下grpc+protobuf 的C++ service的搭建过程,告诉读者在linux系统下怎样实现一个service接口的流程。 一、.proto文件的 实现一个简单的helloworld回显功能,首先需要...

moki_oschina
2018/05/31
301
0
Grpc-Gateway - Grpc兼容HTTP协议文档自动生成网关

因为之前的测试结果让笔者对PHP使用GRPC很失望,如果使用HTTP的方式Guzzle还可以提供并发能力来降低接口消耗,Grpc只能阻塞,但是如果使用HTTP的话对于调用限制和GO调用GO来说不太友好,有没...

喵了_个咪
03/18
529
0

没有更多内容

加载失败,请刷新页面

加载更多

程序设计基础(C)第06讲例程

1summing.c /* summing.c -- 根据用户键入的整数求和 */#include <stdio.h>int main(void){ long num; long sum = 0L; /* 把sum 初始化为0 */ int status; p......

树人大学数字媒体吴凡
7分钟前
3
0
聊聊nacos config的publishConfig

序 本文主要研究一下nacos config的publishConfig ConfigController nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigController.java @Controller@R......

go4it
34分钟前
3
0
Eureka应用注册与集群数据同步源码解析

在之前的EurekaClient自动装配及启动流程解析一文中我们提到过,在构造DiscoveryClient类时,会把自身注册到服务端,本文就来分析一下这个注册流程 客户端发起注册 boolean register() t...

Java学习录
43分钟前
11
0
Java描述设计模式(15):责任链模式

本文源码:GitHub·点这里 || GitEE·点这里 一、生活场景描述 1、请假审批流程 公司常见的请假审批流程:请假天数 当 day<=3 天,项目经理审批当 3<day<=5 天,部门经理审批当 day>5 天...

知了一笑
54分钟前
10
0
总结:数组与链表

1、内存申请:数组在内存上是连续的空间;链表,内存地址上可以是不连续的。 2、查询速度:数组可以随机访问,链表必须顺序访问,即从首个元素开始遍历,逐个查找,所以数组查询很快。 3、写入...

浮躁的码农
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部