Protobuf入门使用

Protobuf

Protobuf安装

安装protobuf

yum install -y autoconf automake libtool curl make g++ unzip
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.10.0/protobuf-all-3.10.0.tar.gz
tar zvxf protobuf-all-3.10.0.tar.gz 
mv protobuf-3.10.0 protobuf
cd protobuf
# 检查环境
./autogen.sh 
# 指定安装路径
./configure --prefix=/usr/local/protobuf
make && make install
#配置环境变量
vi .bashrc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib
export PATH=$PATH:/usr/local/protobuf/bin
source .bashrc
#测试
protoc --version

获取proto包

#Go语言的proto API接口
$ go get -v -u github.com/golang/protobuf/proto

安装protoc-gen-go插件

它是一个 go程序,编译它之后将可执行文件复制到\bin目录。

#安装
$ go get -v -u github.com/golang/protobuf/protoc-gen-go
#编译
$ cd $GOPATH/src/github.com/golang/protobuf/protoc-gen-go/
$ go build
#将生成的 protoc-gen-go可执行文件,放在/bin目录下
$ sudo cp protoc-gen-go /bin/

Protobuf语法

要想使用 protobuf必须得先定义 proto文件。所以得先熟悉 protobuf的消息定义的相关语法

定义一个消息类型

//指定使用proto3语法,如果你没有指定这个,编译器会使用proto2,这个指定语法行必须是文件的非空非注释的第一个行
syntax = "proto3" ;

//package prototext ;
// protoc --go_out=./ *.proto
option go_package = ".;prototext";

message PandaRequest {
    string name = 1;
    int32 shengao = 2;
    repeated int32 tizhong = 3;
    string motto = 4 ;
}

在上面的例子中,所有字段都是标量类型:两个整型(shengao和tizhong),一个string类型(name)。Repeated 关键字表示重复的那么在go语言中用切片进行代表 正如上述文件格式,在消息定义中,每个字段都有唯一的一个标识符.

添加更多消息类型

在一个.proto文件中可以定义多个消息类型。在定义多个相关的消息的时候,这一点特别有用——例如,如果想定义与SearchResponse消息类型对应的回复消息格式的话,你可以将它添加到相同的.proto文件中

syntax = "proto3" ;

//package prototext ;
// protoc --go_out=./ *.proto
option go_package = ".;prototext";

message PandaRequest {
    string name = 1;
    int32 shengao = 2;
    repeated int32 tizhong = 3;
    string motto = 4 ;
}

message PandaResponse { ... }

添加注释

向.proto文件添加注释,可以使用C/C++/java/Go风格的双斜杠(//) 语法格式,

编译.proto

当用protocol buffffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。

对C++来说,编译器会为每个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每一个消息有一个对应的类。 对Python来说,有点不太一样——Python编译器为.proto文件中的每个消息类型生成一个含有静态描述符的模块,,该模块与一个元类(metaclass)在运行时(runtime)被用来创建所需的Python数据访问类。 对go来说,编译器会为每个消息类型生成了一个.pd.go文件。

标准数据类型

一个标量消息字段可以含有一个如下的类型——该表格展示了定义于.proto文件中的类型,以及与之对应的、在自动生成的访问类中定义的类型:

.proto Type Notes C++ Type Java Type Python Type Go Type
double double double float *float64
float float float float *float32
int32 变长编码。 对负数编码是低效的,对于负数用sint32 int32 int int *int32
int64 变长编码。 对负数编码是低效的,对于负数用sint64 int64 long int/long *int64
uint32 变长编码。 uint32 int int/long *uint32
uint64 变长编码。 uint64 long int/long *uint64
sint32 变长编码。 符号int型。比int32,编码负数更高效。 int32 int int *int32
sint64 变长编码。 符号int型。比int64,编码负数更高效。 int64 long int/long *int64
fixed32 四字节。 如果值大于228,比uint32更高效。 uint32 int int/long *uint32
fixed64 八字节。 如果值大于256,比uint64更高效。 uint64 long int/long *uint64
sfixed32 四字节。 int32 int int *int32
sfixed64 八字节。 int64 long int/long *int64
bool bool boolean bool *bool
string UTF-8编码的或7-bit ASCII码文本。 string String str/unicode *string
bytes 字节流。 string ByteString str []byte

默认值

当一个消息被解析的时候,如果被编码的信息不包含一个特定的元素,被解析的对象锁对应的域被设置位一个默认值,对于不同类型指定如下: 对于strings,默认是一个空string 对于bytes,默认是一个空的bytes 对于bools,默认是false 对于数值类型,默认是0

使用其他消息类型

你可以将其他消息类型用作字段类型。例如,假设在每一个PersonInfo消息中包含Person消息,此时可以在相同的.proto文件中定义一个Result消息类型,然后在PersonInfo消息中指定一个Person类型的字段

syntax = "proto3" ;

message PersonInfo {
    repeated Person info =1;
}


message Person {
    string name =1;
    int32 shengao =2;
    repeated int32 tizhong =3;
}

在你的proto3消息中导入proto2的消息类型也是可以的,反之亦然,然后proto2枚举不可以直接在proto3的标识符中使用(如果仅仅在proto2消息中使用是可以的)。

嵌套类型

你可以在其他消息类型中定义、使用消息类型,在下面的例子中,Person消息就定义在PersonInfo消息内,如:

message PersonInfo {
    message Person {
        string name =1;
        int32 shengao =2;
        repeated int32 tizhong =3;
    }
    repeated Person info =1;
}

如果你想在它的父消息类型的外部重用这个消息类型,你需要以PersonInfo.Person的形式使用它,如

message PersonMessage {
PersonInfo.Person info = 1;
}

当然,你也可以将消息嵌套任意多层,如:

message Grandpa { // Level 0
                  message Father { // Level 1
                                   message son { // Level 2
                                                 string name = 1;
                                                 int32 age = 2;
                                   }
                  }
                  message Uncle { // Level 1
                                  message Son { // Level 2
                                                string name = 1;
                                                int32 age = 2;
                                  }
                  }
}

定义服务(Service)

如果想要将消息类型用在RPC(远程方法调用)系统中,可以在.proto文件中定义一个RPC服务接口,protocol buffffer编译器将会根据所选择的不同语言生成服务接口代码及存根。如,想要定义一个RPC服务并具有一个方法,该方法能够接收 SearchRequest并返回一个SearchResponse,此时可以在.proto文件中进行如下定义:

service SearchService {
    //rpc 服务的函数名 (传入参数)返回(返回参数)
    rpc Search (SearchRequest) returns (SearchResponse)
}

最直观的使用protocol buffffer的RPC系统是gRPC一个由谷歌开发的语言和平台中的开源的RPC系统,gRPC在使用protocl buffffer时非常有效,如果使用特殊的protocol buffffer插件可以直接为您从.proto文件中产生相关的RPC代码。

如果你不想使用gRPC,也可以使用protocol buffffer用于自己的RPC实现,你可以从proto2语言指南中找到更多信息

生产访问类

可以通过定义好的.proto文件来生成Java,Python,C++, Ruby, JavaNano, Objective-C,或者C# 代码,需要基

于.proto文件运行protocol buffffer编译器protoc。如果你没有安装编译器,下载安装包并遵照README安装。对于Go,你还需要安装一个特殊的代码生成器插件。你可以通过GitHub上的protobuf库找到安装过程

通过如下方式调用protocol编译器:

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR path/to/file.proto
  • –proto_path

    IMPORT_PATH声明了一个.proto文件所在的解析import具体目录。

    如果忽略该值,则使用当前目录。

    如果有多个目录则可以多次调用–proto_path,它们将会顺序的被访问并执行导入

    -I=IMPORT_PATH是–proto_path的简化形式。

  • 输出路径

    可以提供一个或多个输出路径

    • –cpp_out 在目标目录DST_DIR中产生C++代码,可以在C++代码生成参考中查看更多
    • –python_out 在目标目录 DST_DIR 中产生Python代码,可以在Python代码生成参考中查看更多
    • –go_out在目标目录DST_DIR中产生Go代码,可以在GO代码生成参考中查看更多

注意

如果输出已经存在则会被覆盖,编译器还没有智能到可以追加文件。 - 你必须提议一个或多个.proto文件作为输入,多个.proto文件可以只指定一次。虽然文件路径是相对于当前目录的,每个文件必须位于其IMPORT_PATH下,以便每个文件可以确定其规范的名称。

Protobuf 使用demo

  • 编辑text.proto
syntax = "proto3" ;

//package prototext ;
// protoc --go_out=./ *.proto
option go_package = ".;prototext";

message Test {
    string name = 1;
    int32 shengao = 2;
    repeated int32 tizhong = 3;
    string motto = 4 ;
}
  • 生成访问类
protoc --go_out=./ *.proto
  • 使用生成文件

test.go

package main

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	"test/prototext"
)

func main() {
	text := &prototext.Test{
		Name: "panda黑黑黑",
		Tizhong:[]int32{120,125,198,180,198},
		Shengao:180,
		Motto: "我是谁我在干嘛",

	}

	fmt.Println(text)
	data, e := proto.Marshal(text)
	if e !=nil {
		fmt.Println("编码失败")
	}

	fmt.Println(data)
	newText := &prototext.Test{}
	//proto解码
	err := proto.Unmarshal(data, newText)
	if err !=nil {
		fmt.Println("解码失败")
	}
	fmt.Println(newText)
	fmt.Println(newText.String())
	fmt.Println(newText.Name)
	fmt.Println(newText.Shengao)
	fmt.Println(newText.Tizhong)
	fmt.Println(newText.Motto)

}
原创文章 1 获赞 1 访问量 74

猜你喜欢

转载自blog.csdn.net/weixin_43173303/article/details/105835961