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 Module1
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
21
22syntax = "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.安装grpcGo语言相关库go get google.golang.org/grpcgo get google.golang.org/grpc/cmd/protoc-gen-go-grpc
2.在src目录下新建grpc文件夹,最终的目录结构如下。
3.定义transaction.proto1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17syntax = "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