protobuf使用

  1. 定义proto文件text1.proto

    定义消息类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    syntax = "proto3" ;

    message Test{
    //姓名
    string name = 1;
    //体重
    repeated int32 weight = 2 ;
    //身高
    int32 height =3 ;
    //性别
    string sex = 4 ;
    }
  2. 使用protocol buffer编译器执行以下命令来运行.proto文件,编译器将生成所选语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。对go来说,编译器会为每个消息类型生成一个.pb.go文件。

    1
    2
    $ protoc --go_out=./ *.proto  #不添加grpc插件
    $ protoc --go_out=plugins=grpc:./ *.proto #添加grpc插件

    执行以上命令会将text1.proto文件编译生成以文件text1.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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    // Code generated by protoc-gen-go. DO NOT EDIT.
    // source: text1.proto

    package text1

    import (
    fmt "fmt"
    proto "github.com/golang/protobuf/proto"
    math "math"
    )

    // Reference imports to suppress errors if they are not otherwise used.
    var _ = proto.Marshal
    var _ = fmt.Errorf
    var _ = math.Inf

    // This is a compile-time assertion to ensure that this generated file
    // is compatible with the proto package it is being compiled against.
    // A compilation error at this line likely means your copy of the
    // proto package needs to be updated.
    const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

    type Test struct {
    //姓名
    Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
    //体重
    Weight []int32 `protobuf:"varint,2,rep,packed,name=weight,proto3" json:"weight,omitempty"`
    //身高
    Height int32 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
    //性别
    Sex string `protobuf:"bytes,4,opt,name=sex,proto3" json:"sex,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized []byte `json:"-"`
    XXX_sizecache int32 `json:"-"`
    }

    func (m *Test) Reset() { *m = Test{} }
    func (m *Test) String() string { return proto.CompactTextString(m) }
    func (*Test) ProtoMessage() {}
    func (*Test) Descriptor() ([]byte, []int) {
    return fileDescriptor_c52d883d2746fb54, []int{0}
    }

    func (m *Test) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_Test.Unmarshal(m, b)
    }
    func (m *Test) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_Test.Marshal(b, m, deterministic)
    }
    func (m *Test) XXX_Merge(src proto.Message) {
    xxx_messageInfo_Test.Merge(m, src)
    }
    func (m *Test) XXX_Size() int {
    return xxx_messageInfo_Test.Size(m)
    }
    func (m *Test) XXX_DiscardUnknown() {
    xxx_messageInfo_Test.DiscardUnknown(m)
    }

    var xxx_messageInfo_Test proto.InternalMessageInfo

    func (m *Test) GetName() string {
    if m != nil {
    return m.Name
    }
    return ""
    }

    func (m *Test) GetWeight() []int32 {
    if m != nil {
    return m.Weight
    }
    return nil
    }

    func (m *Test) GetHeight() int32 {
    if m != nil {
    return m.Height
    }
    return 0
    }

    func (m *Test) GetSex() string {
    if m != nil {
    return m.Sex
    }
    return ""
    }

    func init() {
    proto.RegisterType((*Test)(nil), "Test")
    }

    func init() { proto.RegisterFile("text1.proto", fileDescriptor_c52d883d2746fb54) }

    var fileDescriptor_c52d883d2746fb54 = []byte{
    // 110 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2e, 0x49, 0xad, 0x28,
    0x31, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x8a, 0xe1, 0x62, 0x09, 0x49, 0x2d, 0x2e, 0x11,
    0x12, 0xe2, 0x62, 0xc9, 0x4b, 0xcc, 0x4d, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0xb3,
    0x85, 0xc4, 0xb8, 0xd8, 0xca, 0x53, 0x33, 0xd3, 0x33, 0x4a, 0x24, 0x98, 0x14, 0x98, 0x35, 0x58,
    0x83, 0xa0, 0x3c, 0x90, 0x78, 0x06, 0x44, 0x9c, 0x59, 0x81, 0x11, 0x24, 0x0e, 0xe1, 0x09, 0x09,
    0x70, 0x31, 0x17, 0xa7, 0x56, 0x48, 0xb0, 0x80, 0x8d, 0x00, 0x31, 0x93, 0xd8, 0xc0, 0x96, 0x18,
    0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa5, 0x53, 0x6d, 0x33, 0x73, 0x00, 0x00, 0x00,
    }

  3. 定义服务(Service)

    如果想要将消息类型用在 RPC(远程过程调用)系统中,可以在.proto文件中定义一个RPC服务接口,protocol buffe 编译器将会根据所选择的不同语言生成服务接口代码及存根。如想要定义一个RPC服务并具有一个方法,该方法能够接收SearchRequest并返回一个SearchResponse,此时可在.proto文件中进行如下定义:

    1
    2
    3
    4
    service SearchService {
    //rpc 服务的函数名 (传入参数) 返回 (返回参数)
    rpc Search (SearchRequest) returns (SearchResponse);
    }