我是靠谱客的博主 无心画笔,这篇文章主要介绍Golang-RPC(四):golang使用protobuf协议处理数据,现在分享给大家,希望可以做个参考。

我们常用的序列化和反序列化协议有XML, JSON, 以及有些语言所特有的工具比如PHP的serialize。

各个工具都有其特点,比如JSON使用广泛,占用字节较小,但是json串的序列化反序列化效率比较低;而XML虽然解析比较快,但是占用字节较多,太多冗余的字符。那么有没有一种跨语言的不仅占用字节少,而且效率还高的协议呢?

protobuf就是一个比较好的选择。

golang使用protobuf需要先安装 protoc 工具和 protoc-gen-go 代码生成器。

一般我们使用 protoc + protoc-gen-go + proto文件来生成代码。

安装方法:https://blog.csdn.net/raoxiaoya/article/details/109496431

proto语法目前最新版本是proto3。

引入其他proto:import "protos/other.proto";

定义结构体

复制代码
1
2
3
4
5
6
// Person: struct message Person { string name = 1; int64 age = 2; }

定义数组/集合

复制代码
1
2
3
4
5
// persons: []*Person message SliceParam { repeated Person persons = 1; }

定义map

复制代码
1
2
3
4
5
// personInfo: map[string]*Person message MapParam { map<string, Person> personInfo = 1; }

编写 message.proto 文件,在里面定义一个 OrderRequest 结构:

复制代码
1
2
3
4
5
6
7
8
9
10
syntax = "proto3"; package message; //订单请求参数 message OrderRequest { string orderId = 1; int64 timeStamp = 2; }

这个是protobuf的语法,通过 protoc 工具可以生成指定语言的数据结构定义。

执行命令

复制代码
1
2
3
4
5
6
protoc ./message.proto --go_out=./ WARNING: Missing 'go_package' option in "message.proto", please specify it with the full Go package path as a future release of protoc-gen-go will require this be specified.

但是文件还是生产成功了

解决:
在syntax下面添加option信息

复制代码
1
2
option go_package = "aaa;bbb";
复制代码
1
2
3
aaa 表示生成的go文件的存放地址,会自动生成目录的。 bbb 表示生成的go文件所属的包名

默认是当前目录下的message包。

修改 proto 文件:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
syntax = "proto3"; option go_package = "./pbs;message"; package message; //订单请求参数 message OrderRequest { string orderId = 1; int64 timeStamp = 2; }

再次运行 protoc 命令

就能看到生成了 pbs/message.pb.go 文件,内容付在最后。

文件中有一个与 message OrderRequest 结构对应的go结构体:

复制代码
1
2
3
4
5
6
7
8
9
type OrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields OrderId string `protobuf:"bytes,1,opt,name=orderId,proto3" json:"orderId,omitempty"` TimeStamp int64 `protobuf:"varint,2,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` }

这就是经过protobuf转换后的数据结构,我们直接调用即可。

这个文件不需要编辑,在其他地方引用。

接下来将使用两个示例对比json和protobuf在字节占用上的差距。

复制代码
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
38
39
40
41
42
package main import ( "encoding/json" "fmt" "time" "demo1/go-protobuf/pbs" "github.com/golang/protobuf/proto" ) func main() { Test() fmt.Println("--------------------------------------") Test1() } func Test1() { timeStamp := time.Now().Unix() request := &message.OrderRequest{OrderId: "201907310001", TimeStamp: timeStamp} data, _ := proto.Marshal(request) fmt.Println(string(data)) fmt.Println(len(data)) fmt.Println(proto.Size(request)) fmt.Printf("%Tn", data) msgEntity := message.OrderRequest{} proto.Unmarshal(data, &msgEntity) fmt.Println(proto.Size(&msgEntity)) fmt.Println(msgEntity) } func Test() { timeStamp := time.Now().Unix() request := message.OrderRequest{OrderId: "201907310001", TimeStamp: timeStamp} data, _ := json.Marshal(request) fmt.Println(string(data)) fmt.Println(len(data)) fmt.Printf("%Tn", data) }

打印信息:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
{"orderId":"201907310001","timeStamp":1604539977} 49 []uint8 -------------------------------------- 201907310001ɬ��║ 20 20 []uint8 20 {{{} [] [] 0xc00005e500} 20 [] 201907310001 1604539977}

可以看出,使用这个结构来

复制代码
1
2
3
4
5
6
7
8
9
type OrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields OrderId string `protobuf:"bytes,1,opt,name=orderId,proto3" json:"orderId,omitempty"` TimeStamp int64 `protobuf:"varint,2,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` }

来代替我们普通的结构

复制代码
1
2
3
4
5
type OrderRequest struct { OrderId string TimeStamp int64 }

同时,配合使用 github.com/golang/protobuf/proto包的序列化反序列化操作,才是protobuf的应用。使用 json 来序列化和反序列化 message.OrderRequest 对象并没有什么效果。

要知道json比XML本来就小不少,而protobuf比json还要小,有数据显示protobuf对比XML
3 ~ 10
20 ~ 100

关于protobuf的协议参考说明,网上非常多,可自行查阅。

message.pb.go 文件内容:

复制代码
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.25.0 // protoc v3.13.0 // source: message.proto package message import ( proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // This is a compile-time assertion that a sufficiently up-to-date version // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 //订单请求参数 type OrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields OrderId string `protobuf:"bytes,1,opt,name=orderId,proto3" json:"orderId,omitempty"` TimeStamp int64 `protobuf:"varint,2,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` } func (x *OrderRequest) Reset() { *x = OrderRequest{} if protoimpl.UnsafeEnabled { mi := &file_message_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *OrderRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*OrderRequest) ProtoMessage() {} func (x *OrderRequest) ProtoReflect() protoreflect.Message { mi := &file_message_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use OrderRequest.ProtoReflect.Descriptor instead. func (*OrderRequest) Descriptor() ([]byte, []int) { return file_message_proto_rawDescGZIP(), []int{0} } func (x *OrderRequest) GetOrderId() string { if x != nil { return x.OrderId } return "" } func (x *OrderRequest) GetTimeStamp() int64 { if x != nil { return x.TimeStamp } return 0 } var File_message_proto protoreflect.FileDescriptor var file_message_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x46, 0x0a, 0x0c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x70, 0x62, 0x73, 0x3b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_message_proto_rawDescOnce sync.Once file_message_proto_rawDescData = file_message_proto_rawDesc ) func file_message_proto_rawDescGZIP() []byte { file_message_proto_rawDescOnce.Do(func() { file_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_proto_rawDescData) }) return file_message_proto_rawDescData } var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_message_proto_goTypes = []interface{}{ (*OrderRequest)(nil), // 0: message.OrderRequest } var file_message_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_message_proto_init() } func file_message_proto_init() { if File_message_proto != nil { return } if !protoimpl.UnsafeEnabled { file_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OrderRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_message_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_message_proto_goTypes, DependencyIndexes: file_message_proto_depIdxs, MessageInfos: file_message_proto_msgTypes, }.Build() File_message_proto = out.File file_message_proto_rawDesc = nil file_message_proto_goTypes = nil file_message_proto_depIdxs = nil }

最后

以上就是无心画笔最近收集整理的关于Golang-RPC(四):golang使用protobuf协议处理数据的全部内容,更多相关Golang-RPC(四)内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(78)

评论列表共有 0 条评论

立即
投稿
返回
顶部