poroto3 坑 枚举_protobuf3笔记

Protobuf3笔记

文件后缀

定义Proto的文件应以.proto为后缀。

语法版本

Proto文件的首行应指定语法版本:

syntax = "proto3"; // "proto2"

定义字段

在消息中,每个字段以下列方式定义:

type filed "=" tag ";"

如:

message SearchRequest {

string query = 1;

int32 page_number = 2;

int32 result_per_page = 3;

}

标签数字

出于性能考虑,在消息中,常用字段的标签最好小于15。这样可以降低消息序列化后的体积。

多消息

一个Proto文件中,可以定义多个消息。如:

message SearchRequest {

// ...

}

message SearchResponse {

// ...

}

注释

Proto使用C风格的注释。

编译输出

对于C++,protobuf为每个消息生成一个类,为每个proto文件生成一个.h头文件和一个.cc源代码文件。

对Java,protobuf为每个消息生成一个类和一个Builder类。

对于Go,protobuf为每个消息生成一个.pb.go源代码文件和一个结构体。

对Objective-C,protobuf为每个proto文件生成一个pbobjc.h头文件和一个pbobjc.m文件,为每个消息生成一个类。

常用标量类型

bool

string

bytes

int32

int64

uint32

uint64

double

float

默认值

类型

默认值

bool

false

bytes

[]

numeric

0

enum

FirstElement

Field

null

枚举类型

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;

}

message EnumAllowingAlias {

option allow_alias = true;

UNKNOWN = 0;

STARTED = 1;

RUNNING = 1;

}

引用其他消息类型

message SearchResponse {

repeated Result results = 1;

}

message Result {

string url = 1;

string title = 2;

repeated string snippets = 3;

}

引用其他proto文件

import "myproject/other_protos.proto";

protoc参数

-I/–proto_path 指定proto文件目录。

内置类型

message SearchResponse {

message Result {

string url = 1;

string title = 2;

repeated string snippets = 3;

}

repeated Result results = 1;

}

message SomeOtherMessage {

SearchResponse.Result result = 1;

}

更新消息

字段标签

不得改动已存在的字段标签。新生成的代码可以解析旧消息。新增的字段会被设置为默认值。旧代码也可以解析新消息,新增的字段会被忽略。

删除字段

字段可以被删除。但已使用过的标签不得重复使用。

bytes和string

当字符串是UTF-8编码时,bytes和string可以兼容。

Any消息

Any消息是一个占位符,表示任意类型。使用Any消息时,需要引用google/protobuf/any.proto。

import "google/protobuf/any.proto";

message ErrorStatus {

string message = 1;

repeated google.protobuf.Any details = 2;

}

NetworkErrorDetails details = ...;

ErrorStatus status;

status.add_details()->PackFrom(details);

ErrorStatus status = ...;

for (const Any& detail : status.details()){

if (detail.Is()){

NetworkErrorDetails network_error;

detail.UnpackTo(&network_error);

...

}

}

OneOf消息

OneOf提供了一种类似C语言union结构体的机制,来降低存储体积。

message SampleMessage {

oneof test_oneof {

string name = 4;

SubMessage sub_message = 9;

}

}

SampleMessage message;

message.set_name("Joe");

assert(message.has_name());

Map消息

Map可以定义一组键值对。

map projects = 3;

声明包。

package foo.bar;

定义服务

service SearchService {

rpc Search (SearchRequest) returns (SearchResponse);

}

在Go中使用protobuf

示例proto

package tutorial;

option java_package = "com.example.tutorial";

option java_outer_classname = "AddressBookProtos";

message Person {

required string name = 1;

required int32 id = 2;

string email = 3;

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

}

message PhoneNumber {

required string number = 1;

optional PhoneType type = 2 [default = HOME];

}

repeated PhoneNumber phone = 4;

}

生成的代码

调用方法

import (

"github.com/golang/protobuf/proto"

pb "path/to/generated/pb/file"

)

// ...

p := &pb.Person {

Id: 1234,

Name: "John Doe",

Email: "jdoe@example.com",

Phones: []*pb.Person_PhoneNumber {

{Number: "555-4321", Type: pb.Person_HOME},

},

}

out, err := proto.Marshal(p)

q := &pb.Person{}

err := proto.Unmarshal(in, q)

proto.MessageType(name string) reflect.Type

proto.Clone(pb Message) Message

Any消息在Go中的用法

Any消息可以表示任意类型的消息。在Go中使用Any消息的示例如下:

import "github.com/golang/protobuf/ptypes"

import "github.com/golang/protobuf/proto"

import "path/to/generated/pb"

// message Foo {

// google.protobuf.Any bar = 1;

// }

// message Bar {

// uint32 x = 1;

// }

bar := &pb.Bar{

X: 1,

}

body, err := ptypes.MarshalAny(bar)

if err != nil {

log.Fatal(err)

}

foo := &pb.Foo{

Bar: body,

}

注意事项

在使用proto.Unmarshal(buf, message)对消息进行反序列化时,缓冲区buf的长度应当等于消息的实际长度。否则会报告如下错误消息: proto: protocol.Message: illegal tag 0 (wire type 0)

在Java中使用protobuf

示例proto

package tutorial;

option java_package = "com.example.tutorial";

option java_outer_classname = "AddressBookProtos";

message Person {

required string name = 1;

required int32 id = 2;

string email = 3;

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

}

message PhoneNumber {

required string number = 1;

optional PhoneType type = 2 [default = HOME];

}

repeated PhoneNumber phone = 4;

}

生成的代码

// Person

public boolean hasName();

public String getName();

public boolean hasId();

public int getId();

public boolean hasEmail();

public String getEmail();

public List getPhoneList();

public int getPhoneCount();

public PhoneNumber getPhone(int index);

// Person.Builder

public boolean hasName();

public java.lang.String getName();

public Builder setName(String value);

public Builder clearName();

public List getPhoneList();

public int getPhoneCount();

public PhoneNumber getPhone(int index);

public Builder setPhone(int index, PhoneNumber value);

public Builder addPhone(PhoneNumber value);

public Builder addAllPhone(iterable value);

public Builder clearPhone();

调用方法

Person john = Person.newBuilder()

.setId(1234)

.setName("John")

.addPhone(

Person.PhoneNumber.newBuilder()

.setNumber("555-4321")

.setType(Person.PhoneType.HOME))

.build();

john.writeTo(outputStream);

Person walliam = Person.parseForm(inputStream);

使用Gradle生成protobuf

google提供了生成protobuf的gradle插件,名称是com.google.protobuf。在使用时,需要在build.gradle中加入:

buildscript {

repositories {

mavenCentral()

}

dependencies {

classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'

}

}

apply plugin: 'java'

apply plugin: 'com.google.protobuf'

protobuf {

generatedFilesBaseDir = '$projectDir/src'

protoc {

// use local protoc

// path = '/usr/local/bin/protoc'

// or, get from repo

artifact = 'com.google.protobuf:protoc:3.3.0'

}

plugins {

grpc {

artifact = 'io.grpc:protoc-gen-grpc-java:1.4.0'

}

}

generateProtoTasks {

all()*.plugins {

grpc {}

}

}

}

repositories {

mavenCentral()

}

dependencies {

compile 'com.google.protobuf:protobuf-java:3.3.1'

compile 'io.grpc:grpc-netty:1.4.0'

compile 'io.grpc:grpc-protobuf:1.4.0'

compile 'io.grpc:grpc-stub:1.4.0'

/* for Android client, use

compile 'io.grpc:grpc-okhttp:1.4.0'

compile 'io.grpc:grpc-protobuf-lite:1.4.0'

compile 'io.grpc:grpc-stub:1.4.0'

*/

}

sourceSets {

main {

proto {

srcDir 'src/main/protobuf'

include '**/*.proto'

}

}

}

然后执行:

gradle build

如果只需要生成java源代码文件,可以执行:

gradle generateProto

参考资料

修订记录

2016年05月03日 建立文档。

2016年08月11日 修订。

2017年07月28日 改为rst格式。

2017年07月28日 增加gradle部分。

2017年08月04日 修订例子。

2017年08月07日 增加在Go中使用Any消息的例子。

2018年08月06日 修正错别字;修改日期格式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值