Protocol Buffers
Protocol buffers
是由Google推出来的用于描述结构化数据的一种数据格式,类似于XML
,但更小更快更简单,语言无关,平台无关而且支持可扩展。通过描述性语言定义你所需要的数据结构,可以实现一次定义即可以生成多种语言的相关的代码。目前Protocal buffers
基本上已支持大多数的编程语言。
本文将介绍在Go
语言中怎么使用Protocol buffers
1.protoc
安装
下载所需的版本,解压设置环境变量
2.protoc-gen-go
的安装
go install google.golang.org/protobuf/cmd/protoc-gen-go
3.新建一个Go Module
1
2
3
4
5➜ gopro mkdir grpc
➜ gopro cd grpc
➜ grpc mkdir src
➜ cd src
➜ src go mod init example.com/grpc
整个目录的结构如下
4.在protofiles
中编辑person.pb.go
文件。如下代码用protobuf
声明式语言定义了一个数据结构1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21syntax = "proto3";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
5.通过proto
生成Go
语言对应的文件
在grpc/src/protofiles
执行protoc --go_out=. *.proto
会在当前目录下生成
文件person.pb.go
6.编写main.go
和main_json.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// main.go
package main
import (
pb "example.com/grpc/protofiles" //我们可以使用person.pb.go中的结构傅Person
"fmt"
"github.com/golang/protobuf/proto"
)
func main() {
// 对Person进行初始化,并将指针赋值给变量p
p := &pb.Person{
Id: 1234,
Name: "Roger F",
Email: "rf@gmail.com",
Phones: []*pb.Person_PhoneNumber{
{Number: "555-4321", Type: pb.Person_HOME},
},
}
p1 := &pb.Person{}
body, _ := proto.Marshal(p)
_ = proto.Unmarshal(body, p1)
fmt.Println("Original struct loadef from proto file:",p,"\n")
fmt.Println("Marshaled proto data: ", body, "\n")
fmt.Println("Unmarshaled struct: ", p1)
}
1 | // main_json.go |
7.执行go mod tidy
安装依赖。
8.分别执行main.go
和main_json.go
Go类型与对应的Protobuf类型
Go | Protobuf type |
---|---|
float32 | float |
float64 | double |
uint32 | fixed32 |
uint64 | fixed64 |
[]byte | bytes |
Protobut type | Default value |
---|---|
string | “” |
bytes | empty bytes[] |
bool | false |
int,int32,int64,float,double | 0 |
enum | 0 |
GRPC
1.安装grpc
Go语言相关库go get google.golang.org/grpc
go get google.golang.org/grpc/cmd/protoc-gen-go-grpc
2.在src
目录下新建grpc
文件夹,最终的目录结构如下。
3.定义transaction.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16syntax = "proto3";
package grpc;
message TransactionRequest {
string from = 1;
string to = 2;
float amount = 3;
}
message TransactionResponse {
bool confirmation = 1;
}
service MoneyTransaction {
rpc MakeTransaction(TransactionRequest) returns (TransactionResponse) {}
}
4.执行命令protoc --go_out=plugins=grpc:. transaction.proto
,会在grpc
目录下生成文件transaction.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
38type TransactionRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"`
To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"`
Amount float32 `protobuf:"fixed32,3,opt,name=amount,proto3" json:"amount,omitempty"`
}
type TransactionResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Confirmation bool `protobuf:"varint,1,opt,name=confirmation,proto3" json:"confirmation,omitempty"`
}
type moneyTransactionClient struct {
cc grpc.ClientConnInterface
}
func NewMoneyTransactionClient(cc grpc.ClientConnInterface) MoneyTransactionClient {
return &moneyTransactionClient{cc}
}
func (c *moneyTransactionClient) MakeTransaction(ctx context.Context, in *TransactionRequest, opts ...grpc.CallOption) (*TransactionResponse, error) {
out := new(TransactionResponse)
err := c.cc.Invoke(ctx, "/grpc.MoneyTransaction/MakeTransaction", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func RegisterMoneyTransactionServer(s *grpc.Server, srv MoneyTransactionServer) {
s.RegisterService(&_MoneyTransaction_serviceDesc, srv)
}
5.编写client.go
和server.go
1 | // server.go |
1 | // client.go |
6.分别执行server.go
和client.go
Ref:
1.https://developers.google.com/protocol-buffers/docs/gotutorial
2.Building RESTful Web services with Go
3.GRPC