protobuf
Protocol Buffer其实是google出品的一种轻量高效的结构化数据存储格式,性能比xml,json强大很多
protobuf经历了protobuf2和protobuf3,pb3比pb2简化了许多,目前主流的是pb3
protobuf的语法
要想使用 protobuf必须得先定义 proto文件。所以得先熟悉 protobuf的消息定义的相关语法。
定义一个消息类型
message TestRequest{
string name =1;//name表示名称,name的编号是1,而不是赋值
int32 shenggao =2;
//repeated相当于切片
repeated int32 tizhong =3;
}
单文件多消息
syntax = "proto3";
message PandaRequest {
string name = 1;
int32 shengao = 2;
int32 tizhong = 3;
}
message PandaResponse {
...
}
从.proto文件生成了什么?
标准数据类型
.proto Type | Notes | C++ Type | Python Type | Go Type |
---|---|---|---|---|
double | double | float | float64 | |
float | float | float | float32 | |
int32 | 使用变长编码,对于负值的效率很低,如果你的域有 可能有负值,请使用sint64替代 | int32 | int | int32 |
uint32 | 使用变长编码 | uint32 | int/long | uint32 |
uint64 | 使用变长编码 | uint64 | int/long | uint64 |
sint32 | 使用变长编码,这些编码在负值时比int32高效的多 | int32 | int | int32 |
sint64 | 使用变长编码,有符号的整型值。编码时比通常的 int64高效。 | int64 | int/long | int64 |
fixed32 | 总是4个字节,如果数值总是比总是比228大的话,这 个类型会比uint32高效。 | uint32 | int | uint32 |
fixed64 | 总是8个字节,如果数值总是比总是比256大的话,这 个类型会比uint64高效。 | uint64 | int/long | uint64 |
sfixed32 | 总是4个字节 | int32 | int | int32 |
sfixed64 | 总是8个字节 | int64 | int/long i | int64 |
bool | bool | bool | bool | |
string | 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文 本。 | string | str/unicode | string |
bytes | 可能包含任意顺序的字节数据。 | string | str | []byte |
默认值
使用其他消息类型
message PersonInfo {
repeated Person info = 1;
}
message Person {
string name = 1;
int32 shengao = 2;
repeated int32 tizhong = 3;
}
嵌套类型
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)
service SearchService {
//rpc 服务的函数名 (传入参数)返回(返回参数)
rpc Search (SearchRequest) returns (SearchResponse);
}
生成访问类(了解)
可以通过定义好的.proto文件来生成Java,Python,C++, Ruby, JavaNano, Objective-C,或者C# 代码,需要基
于.proto文件运行protocol buffer编译器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
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代码生成参考中查看更多。 作为一个方便的拓展,如果DST_DIR以.zip或者.jar结尾,编译器会将输出写到一个ZIP格式文件或者符合JAR标准的.jar文件中。注意如果输出已经存在则会被覆盖,编译器还没有智能到可以追加文件。-你必须提议一个或多个.proto文件作为输入,多个.proto文件可以只指定一次。虽然文件路径是相对于当前目录的,每个文件必须位于其IMPORT_PATH下,以便每个文件可以确定其规范的名称。
基本案例
syntax ="proto3";
package one;
message TestRequest{
string name =1;
int32 shenggao =2;
//repeated相当于切片
repeated int32 tizhong =3;
}
message TestResponse{
int32 err =1;
string ermessage =2;
}
protobuf做数据格式转换
package main
import (
"proto1/one"
"fmt"
"github.com/golang/protobuf/proto"
)
func main() {
info:=&one.TestRequest{
Name:"zq",
Tizhong:[]int32{120,150},
Shenggao:180,
}
fmt.Println(info) //name:"zq" shenggao:180 tizhong:120 tizhong:150
//编码
bytes, err := proto.Marshal(info)
if err!=nil{
fmt.Println("编码失败")
}
fmt.Println(bytes) //[10 2 122 113 16 180 1 26 3 120 150 1]
newinfo:=&one.TestRequest{}
//解码
err= proto.Unmarshal(bytes, newinfo)
if err!=nil{
fmt.Println("解码失败")
}
fmt.Println(newinfo) //name:"zq" shenggao:180 tizhong:120 tizhong:150
//分别获取属性值
fmt.Println(newinfo.Shenggao,newinfo.Tizhong,newinfo.Name)
}