[toc]
ProtoBuf使用
安装
安装ProtoBuf,然后需要配置环境变量
protoc帮助命令,运行成功表示安装成功。
去github搜索grpc-gateway
有下面的安装教程
1 2 3 4 5
| go install \ github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \ github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \ google.golang.org/protobuf/cmd/protoc-gen-go \ google.golang.org/grpc/cmd/protoc-gen-go-grpc
|
如果不行,就一个一个安装。
hello world
创建proto
文件夹,创建trip.proto
文件
在vscode安装proto3插件。
在trip.proto
文件中写如下代码:
1 2 3 4 5 6 7 8 9 10 11
| syntax = "proto3"; package coolcar; option go_package="coolcar/proto/gen/g0;trippb";
message Trip{ string start = 1; string end = 2; int64 duration_sec = 3; int64 fee_cent = 4; }
|
进入proto
文件夹目录,命令行操作
1 2
| -I表示输入目录=.表示当前目录go_out表示生成go语言的代码paths=source_relative:gen/go表示生成文件的存储路径,最后加上源文件trip.proto protoc -I=. --go_out=paths=source_relative:gen/go trip.proto
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import( trippb "coolcar/proto/gen/go" "fmt" ) func main(){ trip:= trippb.Trip{ Start: "abc", End: "def", DurationSec: 3600, FeeCent: 10000, } fmt.Println(&trip) }
|
序列化,反序列化二进制流
序列化
1 2 3 4 5
| b, err := proto.Marshal(&trip) if err !=nil { panic(err) } fmt.Printf("%X\n",b)
|
反序列化
1 2 3 4 5 6
| var trip2 trippb.Trip err = protp.Unmarshal(b, &trip2) if err!= nil{ panic(err) } fmt.Println(&trip2)
|
这也就是服务器和客户端通信的过程:通过Marshal
出来的二进制流通过grpc
服务的TCP端口发给客户端,客户端Unmarshal
就可以获得数据
json.Marshal
转json数据
1
| b,err = json.Marshal(&trip2)
|
补充
更多的数据字段
bytes就是和穿多媒体内容
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
| syntax = "proto3"; package coolcar; option go_package="coolcar/proto/gen/g0;trippb";
message Location{ double latitude=1; double longtitude=2; }
enum TripStatus{ TS_NOT_SPECIFIDE = 0 NOT_STARTED = 1; IN_PROGRESS = 2; FINISHED = 3; PAID = 4; } message Trip{ string start = 1; string end = 2; int64 duration_sec = 3; int64 fee_cent = 4; Location start_pos = 5; repeated Location path_locations= 7; TripStatus status = 8; }
|
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
| func main(){ trip:= trippb.Trip{ Start: "abc", End: "def", DurationSec: 3600, FeeCent: 10000, StartPos: &trippb.Location{ Latitude: 32, Longtitude: 120, }, EndPos: &trippb.Location{ Latitude: 35, Longtitude: 111, }, PathLocations: []*trippb.Location{ { Latitude: 23, Longtitude: 111, }, { Latitude: 15, Longtitude: 131, }, }, Status: trippb.TripStatus_IN_PROGRESS, } fmt.Println(&trip) }
|
ProtoBuf字段的可选性
每个字段都是可填可不填的。ProtoBuf规定了数据在网络上传输的具体格式,但是随着系统的更新,格式是不固定的,需要增加的。新老系统同时存在是非常普遍的问题。新老系统的交替,导致字段不一致的问题。
ProtoBuf的处理方式:
- 新系统数据到老系统,出现的新字段,ProtoBuf不理。
- 老系统数据到新系统,老系统没有的字段数值为零值(比如空字符串,false,0)。
当出现零值之后,序列化就不会有零值的字段。
所以在定义字段的时候,一定要考虑零值代表的意思。