G

[Golang] gRPC proto文件解读

RoLingG gRPC 2024-06-07

proto文件解读

syntax = "proto3"; //指定proto版本
package hello_proto;  //指定默认包名

//指定golang包名
option go_package = "/hello_proto"; //在hello.proto文件所在的目录下生成一个名为hello_proto的目录存放.pb.go文件
//option go_package = ".;xxx";  这样写,是在hello.proto文件所在的目录下直接生成.pb.go文件,文件的包名为xxx

//定义rpc服务
//service 对应的是go语言的接口interface
service HelloService {
  //定义函数/方法
  //rpc对应的是go结构体中的方法
  rpc SayHello (HelloRequest) returns (HelloResponse) {}
}

//HelloRequest 请求内容
//message对应的是go的struct
message HelloRequest {
  string name = 1;
  string message = 2;
}

//HelloResponse 回应内容
message HelloResponse {
  string name = 1;
  string message = 2;
}
  • 对比原始的 rpc 就会发现,proto 文件直接定义好了请求和接收体,不用在服务端和客户端程序去进行重复的编写。
  • 而且 函数/方法 也是在 proto 里面就定义好了,能被编译器进行读取进行代码提示,编写代码难度和复杂度都降低了。
  • 整体只用编写 proto 文件、客户端和服务端程序就行了,proto 文件对应的代码都是用 cmd 自己生成的,一般不需要开发者关心。

    protoc -I . --go_out=plugins=grpc:./grpc/grpc_proto .\grpc\grpc_proto\hello.proto    
    //在当前目录下的grpc目录里的grpc_proto目录生成grpc目录下的grpc_proto目录下的hello.proto文件的.proto文件
  • 函数/方法 的请求体和返回体都说明好了,直观又易读。
  • 重要的是 grpc 跨语言 !

其中,proto文件内有多个不同的service又叫多服务。例如:

syntax = "proto3";

option go_package = "/multservice_proto";

service VideoService {
  rpc Watch (Request) returns (Response) {}
}

service OrderService {
  rpc Buy (Request) returns (Response) {}
}

message Request {
  string name = 1;
  string message = 2;
}

message Response {
  string name = 1;
  string message = 2;
}

proto文件基本的数据类型

message Request {
  double a1 = 1;  float64
  float a2 = 2; float32
  int32 a3 = 3; int32
  uint32 a4 = 4;  uint32
  uint64 a5 = 5;  uint64
  sint32 a6 = 6;  int32
  sint64 a7 = 7;  int64
  fixed32 a8 = 8; uint32
  fixed64 a9 = 9; uint64
  sfixed32 a10 = 10;  int32
  sfixed64 a11 = 11;  int64
  bool a12 = 12;  bool
  string a13 = 13;  string
  bytes a14 = 14; 对应[]byte
}

go对应类型

type Request struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    A1  float64 `protobuf:"fixed64,1,opt,name=a1,proto3" json:"a1,omitempty"`
    A2  float32 `protobuf:"fixed32,2,opt,name=a2,proto3" json:"a2,omitempty"`
    A3  int32   `protobuf:"varint,3,opt,name=a3,proto3" json:"a3,omitempty"`
    A4  uint32  `protobuf:"varint,4,opt,name=a4,proto3" json:"a4,omitempty"`
    A5  uint64  `protobuf:"varint,5,opt,name=a5,proto3" json:"a5,omitempty"`
    A6  int32   `protobuf:"zigzag32,6,opt,name=a6,proto3" json:"a6,omitempty"`
    A7  int64   `protobuf:"zigzag64,7,opt,name=a7,proto3" json:"a7,omitempty"`
    A8  uint32  `protobuf:"fixed32,8,opt,name=a8,proto3" json:"a8,omitempty"`
    A9  uint64  `protobuf:"fixed64,9,opt,name=a9,proto3" json:"a9,omitempty"`
    A10 int32   `protobuf:"fixed32,10,opt,name=a10,proto3" json:"a10,omitempty"`
    A11 int64   `protobuf:"fixed64,11,opt,name=a11,proto3" json:"a11,omitempty"`
    A12 bool    `protobuf:"varint,12,opt,name=a12,proto3" json:"a12,omitempty"`
    A13 string  `protobuf:"bytes,13,opt,name=a13,proto3" json:"a13,omitempty"`
    A14 []byte  `protobuf:"bytes,14,opt,name=a14,proto3" json:"a14,omitempty"`
}

数组类型

message Request {
    string xxx = 1;
    fixed32 code = 2;
}

message ArrayRequest {
    repeated int64 a1 = 1;
    repeated string a2 = 2;
    repeated Request request_list = 3;
}

go对应类型

type ArrayRequest struct {
    A1          []int64
    A2          []string
    RequestList []*Request
}

map类型

键(key)只能是基本类型

message MapRequest {
    map<int64, string> m_i_s = 1;
    map<string, bool> m_i_b = 2;
    map<string, Request> m_i_arr = 3;
}

go对应类型

type MapRequest struct {
    MIS   map[int64]string
    MIB   map[string]bool
    MIArr map[string]*ArrayRequest
}

嵌套类型

message Q1 {
    message Q2{
        string name2 = 2;
    }
    string name1 = 1;
    Q2 q2 = 2;
}

与上同样,几乎没差别,明显的看出来下面这种写法更易读

message Q2 {
    string name2 = 2;
}
message Q1 {
    string name1 = 1;
    Q2 q2 = 2;
}

对应go类型

type Q1 struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields
    
    Name1 string `protobuf:"bytes,1,opt,name=name1,proto3" json:"name1,omitempty"`
    Q2    *Q1_Q2 `protobuf:"bytes,2,opt,name=q2,proto3" json:"q2,omitempty"`

}

编写风格

  • 文件名建议下划线,例如:my_student.proto
  • 包名和目录名对应
  • 服务名、方法名、消息名均为大驼峰
  • 字段名为下划线,小驼峰。但实际自己生成会将下划线去掉,然后将下划线之后的第一个字母大写。
PREV
[Golang] gRPC框架 gRPC前瞻
NEXT
[Golang] gRPC 四种传输方式

评论(0)

发布评论