4、protobuf进阶


一、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中修改导入的位置,如图
//hello.proto
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;
}

//base.proto
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的importimport "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() {
	//stream
	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)
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无休止符

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值