本文主要分享【protobuf3教程】,技术文章【4、protobuf进阶】为【无休止符】投稿,如果你遇到Go微服务实战-电商系统相关问题,本文相关知识或能到你。protobuf3教程目
本文主要分享【protobuf 3教程】,技术文章【4、protobuf进阶】为【无休止符】投稿,如果你遇到Go微服务实战-电商系统相关问题,本文相关知识或能到你。
protobuf 3教程
目录 一、proto的类型二、option go_package三、proto文件import另外一个文件的message四、message嵌套五、enum使用六、map使用七、proto的内置timestamp
protobuf官方文档参考:http://developers.google.com/protocol-buffers/docs/proto3
一、proto的类型
proto的默认数值类型:当一个消息被解析的时候,如果被编码的信息不包含一个特定的singular元素,被解析的对象锁对应的域被设置为一个默认值,对于不同类型指定如下 对于strings,默认值是一个空string对于bytes,默认值是一个空的bytes对于bools,默认值是false对于数值类型,默认是0对于枚举,默认是第一个定义的枚举值,必须为0
二、option go_package
我们之前在stream.proto中配置的包路径为:option go_package = ".;proto";
,这时候生成的proto文件路径是跟stream.proto同级目录下
对应的生成命令是:
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative *.proto
这时候思考,如果我们希望将pb.go生成到其他路径:
修改option go_package配置:
option go_package = "common/stream/proto/v1";
生成命令:注意这时候不应该再使用source_relative,而应该使用import,如
protoc --go_out=. --go_opt=paths=import --go-grpc_out=. --go-grpc_opt=paths=import *.proto
如果我们希望生成到根目录的其他路径
修改option go_package配置:
option go_package = "../../common/stream/proto/v1";
生成命令:注意这时候不应该再使用source_relative,而应该使用import,如
protoc --go_out=. --go_opt=paths=import --go-grpc_out=. --go-grpc_opt=paths=import *.proto
三、proto文件import另外一个文件的message
hello.proto
syntax = "proto3";
import "base.proto";
option go_package = ".;proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc Ping(Empty) returns (Pong);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
base.proto:比较公用的message
syntax = "proto3";
message Empty{
}
message Pong{
}
实际上谷歌已经自定义了Empty:而且还包含很多其他的内置message
修改后的proto:注意需要在golang中修改导入的位置,如图
syntax = "proto3";
import "base.proto";
import "google/protobuf/empty.proto";
option go_package = ".;proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc Ping(google.protobuf.Empty) returns (Pong);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
syntax = "proto3";
message Pong{
}
四、message嵌套
message嵌套
message HelloReply {
string message = 1;
message Result {
string name = 1;
string url = 2;
}
repeated Result data = 2;
}
嵌套后生成的pb.go代码是:
HelloReply_Result
type HelloReply_Result struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
}
五、enum使用
hello.proto
message HelloRequest {
string name = 1;
string url = 2;
Gender g = 3;
}
enum Gender{
MALE = 0;
FEMALE = 1;
}
hello.pb.go
type Gender int32
const (
Gender_MALE Gender = 0
Gender_FEMALE Gender = 1
)
client.go
c := proto.NewGreeterClient(conn)
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "test",
Url: "hel.com",
G: proto.Gender_FEMALE,
})
六、map使用
hello.proto
message HelloRequest {
string name = 1;
string url = 2;
Gender g = 3;
map<string, string> mp = 4;
}
hello.pb.go
type HelloRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
G Gender `protobuf:"varint,3,opt,name=g,proto3,enum=Gender" json:"g,omitempty"`
Mp map[string]string `protobuf:"bytes,4,rep,name=mp,proto3" json:"mp,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
client.go
c := proto.NewGreeterClient(conn)
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "test",
Url: "hel.com",
G: proto.Gender_FEMALE,
Mp: map[string]string{
"name": "test",
"company": "my",
},
})
七、proto的内置timestamp
timestamp的import:
import "google/protobuf/timestamp.proto";
hello.proto的定义:内置类型都需要
google.protobuf
开头
syntax = "proto3";
import "base.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
option go_package = ".;proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc Ping(google.protobuf.Empty) returns (Pong);
}
message HelloRequest {
string name = 1;
string url = 2;
Gender g = 3;
map<string, string> mp = 4;
google.protobuf.Timestamp addTime = 5;
}
enum Gender{
MALE = 0;
FEMALE = 1;
}
message HelloReply {
string message = 1;
message Result {
string name = 1;
string url = 2;
}
repeated Result data = 2;
}
hello.pb.go:可以看到AddTime的类型是
*timestamppb.Timestamp
,点击后查看import就是client.go需要import的包名
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
type HelloRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
G Gender `protobuf:"varint,3,opt,name=g,proto3,enum=Gender" json:"g,omitempty"`
Mp map[string]string `protobuf:"bytes,4,rep,name=mp,proto3" json:"mp,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
AddTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=addTime,proto3" json:"addTime,omitempty"`
}
client.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/types/known/timestamppb"
"time"
"MyTestProject/grpc_test/proto"
)
func main() {
conn, err := grpc.Dial("127.0.0.1:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
fmt.Println(err.Error())
return
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "test",
Url: "hel.com",
G: proto.Gender_FEMALE,
Mp: map[string]string{
"name": "test",
"company": "my",
},
AddTime: timestamppb.New(time.Now()),
})
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(r.Message)
}
本文《4、protobuf进阶》版权归无休止符所有,引用4、protobuf进阶需遵循CC 4.0 BY-SA版权协议。