一.protobuf简介

  1. 前言

移动互联网时代
手机流量
电量是最为有限资源,而移动端的即时通讯应用无疑必须得直面这两点解决流量过大的基本方法就是
使用高度压缩通信协议,而数据压缩流量减小带来的自然结果就是省电:因为大数据量传输必然需要
更久的网络操作
数据序列化
序列化操作,这些都是电量消耗过快的根源。当前即时通讯应用中最热门的
通信协议无疑就是
Google的Protobuf了,基于它的优秀表现,
微信手机QQ这样的主流IM应用也早已在使用

  1. 简介

Protobuf
Protocol Buffers的简称,它是Google公司开发的一种
数据描述语言,是一种
轻便高效
结构化数据存储格式可以
用于结构数据,或者说
序列化,它很适合做
数据存储
RPC 数据交换格式,可用于
通讯协议
数据存储领域语言无关、平台无关、可扩展
序列化结构数据格式,是一种
灵活
高效
自动化机制用于
序列化结构数据,对比于 XML和JSON,它
更小、更快
简单,总之它是
服务需要使用的东西.
目前提供了 C++、Java、Python 三种语言的 API(即时通讯网注:Protobuf官方工程主页显示的已支持开发语言多达10种,分别有:C++、Java、Python、Objective-C、C#、JavaNano、JavaScript、Ruby、Go、PHP,基本上主流的语言都已支持).

Protobuf开源时的定位类似于XML、JSON等数据描述语言通过
附带工具生成代码
实现结构化数据序列化功能.这里关注的是Protobuf作为
接口规范描述语言可以
作为设计安全的跨语言RPC接口的基础工具

  1. 需要了解几点

  1. protobuf的优势和劣势

(1).优势

(2).劣势

二.protobuf安装

  1. windows电脑上面安装protocol buffers

github地址
https://github.com/protocolbuffers/protobuf

版本下载地址
https://github.com/protocolbuffers/protobuf/tags

(1).下载

这里下载protobuf v3.15.5 的版本下载地址
https://github.com/protocolbuffers/protobuf/releases/tag/v3.15.5选择
protoc-3.15.5-win64.zip
下载,减压并将解压得到的文件中的bin目录路径添加系统变量

1).官网下载
2).解压
3).添加环境变量

环境变量添加操作文档:
安装ElasticSearch之前的准备工作jdk的安装


系统变量找到Path
,把
bin目录路径添加
,然后完成可以

4).重启计算机

配置环境变量,为了使其生效,需要重启计算机

(2).查看版本

出现以下显示,说明protobuf 安装成功

(3).protobuf的go语言插件protocgen-go插件

go install github.com/golang/protobuf/protoc-gen-go@latest

安装结果如下:

F:wwwgo-datasrcgo_codemicro>go install github.com/golang/protobuf/protoc-gen-go@latest
go: downloading github.com/golang/protobuf v1.5.3
go: downloading google.golang.org/protobuf v1.26.0

F:wwwgo-datasrcgo_codemicro>
  1. Mac电脑上面安装protocol buffers

Linux和Mac安装方式类似

(1).方式一:安装protobuf (推荐)

如果电脑上面没有brew先安装brew

brew install protobuf

(2).方式二:安装protobuf

如果电脑没有安装brew可以使用下面方法安装

(1).下载

下载地址
https://github.com/protocolbu%EF%AC%80ers/protobuf/releases

选择适合macos的protobuf,比如选择protoc-3.12.1-osxx86_64.zip

(2).解压

解压包得到protoc-3.12.1-osxx86_64

(3).重命名
mv protoc-3.12.1-osx-x86_64 protobuf
(4).配置环境变量
vim ~/.bash_profile

export PROTOBUF=/Users/nacos/Library/protobuf
export PATH=$PATH:$PROTOBUF/bin
(5).刷新配置
source ~/.bash_profile
(6).查看版本
protoc --version

(3).protobuf的go语言插件protoc-gen-go插件

go install github.com/golang/protobuf/protoc-gen-go@latest

(4).配置环境变量

安装完毕后如果提示
没法使用protoc-gen-go,还需要
gopath对应bin目录配置到环境变量

vim ~/.bash_profile

export PATH=/Users/nacos/go/bin:$PATH

(5).刷新配置

配置完保存记得刷新下配置

source ~/.bash_profile
  1. 测试protoc和protoc-gen-go是否全部配置成功

(1).新建 test.proto

syntax = "proto3";
option go_package = "./protoService";
message Userinfo {
    string name = 1;
    int32 age = 2;
    repeated string hobby = 3;
}

(2).把proto 文件编译成go文件

F:wwwgo-datasrcgo_codemicroprotoc>protoc --go_out=./ *.proto

(3).结果

运行以上命令后,正确的结果如下:

三.protobuf 的用法

参考文档(需科学上网):
https://developers.google.com/protocol-buffers/docs/proto3

  1. protobuf 简单语法

(1).案例引入

先看代码然后根据代码讲解,创建一个后缀为.proto的protobuf语法的文件,如下

syntax = "proto3";  //指定版本信息,不指定会报错默认是proto2

//分号(;)前面表示当前.proto文件所在的路径,分号后面表示生成go文件的包名
option go_package = "./proto;helloworld";

//message定义一种消息类型关键字message定义结构,并且结构可以嵌套定义结构,message定义内容生成一个结构体
message Person{
    //名字
    string name = 1;
    //年龄
    int32 age = 2 ;
    //爱好
    repeated string hobby = 3; // repeadted关键字类似与go中的切片编译之后对应的也是go的切片,golang中会生成string类型切片
}

(2).总结

(3).message的格式说明

消息
至少一个字段组合而成,类似于Go语言中的
结构体每个字段都有一定的格式:

//注释格式 注释尽量也写在内容上方
(字段修饰符数据类型 字段名称 = 唯一编号标签值;
message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
 
message SearchResponse {
 ...
}

message常见数据类型与go中类型对比

(4).proto2和proto3差别

proto3 比 proto2 支持更多语言但
简洁去掉了一些复杂的语法和特性,更
强调约定
弱化语法

区别

在 proto2 中,需要明确使用 [packed=true] 来为字段指定比较紧凑的 packed 编码方式

  • proto2可以选填default而proto3只能使用系统默认

在 proto2 中,可以使用
default 选项为某一字段指定默认值
在 proto3 中,字段的默认值只能根据字段类型由系统决定,也就是说,
默认值全部是约定好的,而不再提供指定默认值的语法

proto3字段规则
  • singular: 可以有零个或其中一个字段(但不超过一个)

在proto2中,规则为:

required:必须有一个

optional:0或者1个

repeated:任意数量(包括0)

  1. protobuf高级用法

(1).message嵌套

messsage除了能放
简单数据类型外,还能存放
另外的message类型,如下:

syntax = "proto3";//指定版本信息,不指定会报错
option go_package = "./proto;helloworld";

//message为关键字,作用为定义一种消息类型
message Person{
    //名字
    string name = 1;
    //年龄
    int32 age = 2 ;
    //定义一个message
    message PhoneNumber {
        string number = 1;
        int64 type = 2;
    }
    PhoneNumber phone = 3;
}

(2).repeated关键字

repeadted关键字类似与
go中的切片编译之后对应的也是go的切片用法如下

syntax = "proto3";//指定版本信息,不指定会报错
option go_package = "./proto;helloworld";

//message为关键字,作用为定义一种消息类型
message Person{
    //名字   
    string name = 1;
    //年龄    
    int32 age = 2 ;
    //定义一个message
    message PhoneNumber {
        string number = 1;
        int64 type = 2;
    }
    // repeated: 该字段可以重复任意次数(包括零次)。重复值的顺序将被保留
    repeated PhoneNumber phone = 3;
}

(3).默认值

解析 message 时,如果被编码的 message 里没有包含某些变量,那么根据类型不同他们会有不同的默认值,具体如下:

  • repeated字段默认值是空列表

收到数据后反序列化后,对于
标准值类型的数据,比如bool,如果它的值是 false,那么就无法判断这个值是对方设置的,还是对方压根就没给这个变量设置

(4).enum关键字

在定义消息类型时,可能会希望其中一个字段有一个
预定义的值列表,比如说,电话号码字段有个类型,这个类型可以是:home,work,mobile,可以通过enum在消息定义中添加每个可能值的常量来非常简单的执行操作,实例如

syntax = "proto3";//指定版本信息,不指定会报错

package pb;//后期生成go文件的包名

//message为关键字,作用为定义一种消息类型
message Person{    
    //名字
    string name = 1;
    //年龄
    int32 age = 2 ;

    //定义一个message
    message PhoneNumber {
        string number = 1;
        PhoneType type = 2;
    }

    repeated PhoneNumber phone = 3;
    
    // 枚举:可以在message内定义
    enum Corpus {
        UNIVERSAL = 0;
        WEB = 1;
        IMAGES = 2;
        LOCAL = 3;
        NEWS = 4;
        PRODUCTS = 5;
        VIDEO = 6;
    }
    Corpus corpus = 4;
}

//enum为关键字,作用为定义一种枚举类型,可以在message外定义
enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
}

如上,enum
第一个常量映射为0每个枚举定义
必须包含一个映射到零的常量作为其
第一个元素,这是因为:

必须有一个零值,以便可以使用0作为数字
默认值

零值必须是第一个元素,以便与proto2语义
兼容,其中第一个枚举值始终是默认值

枚举值不能重复,除非使用
option allow_alias = true 选项来开启别名:

enum EnumAllowingAlias {

option allow_alias = true;

UNKNOWN = 0;

STARTED = 1;

RUNNING = 1;.

}

枚举定义在一
个消息内部或消息外部都是可以的,如果枚举是 定义在 message 内部,而其他message又想使用,那么可以通过
MessageType.EnumType 的方式引用

(5).定义RPC服务

如果需要将message与
RPC一起使用,则可以在 .proto 文件中
定义RPC服务接口,protobuf编译器将根据选择的语言生成RPC接口代码,示例如下:

//定义RPC服务
service HelloService {
    rpc Hello (Person)returns (Person);
}

定义一个RPC的服务

syntax = "proto3";

option go_package = "./sayService";

service sayService {
    rpc SayHello(HelloRequest) returns (HelloRes)
}

message HelloRequest {
    string name = 1;
}

message HelloRes {
    string message = 1;
}

生成go文件命令:

生成
带RPC服务相关的需要使用以下命令

protoc --go_out=plugins=grpc:. *.proto

(6).案例总结

syntax = "proto3";

//声明是为了防止不同项目之间命名冲突,编译生成的类将被放置在一个与 package 名相同命名空间中
package tutorial;

message Student {
    // 字段编号:消息定义中的每个字段都有一个唯一编号,这些字段编号用于以二进制格式标识您的字段,一旦您的消息类型被使用,就不应该更改
    uint64 id = 1;
    string name = 2;
    // singular修饰符修饰的字段可以是0次或者1次,但是当定制协议,用该修饰符修饰的字段都报错
    // singular string email = 3;
    string email = 3;
    
    enum PhoneType {
        MOBILE     = 0; //proto3版本中,首成员必须为0,成员不应有相同的值
        HOME     = 1;
    }
    
    message PhoneNumber { 
        string number     = 1;
        PhoneType type = 2;
    }
    // repeated: 该字段可以重复任意次数(包括零次),重复值的顺序将被保留
    repeated PhoneNumber phone = 4;
}
  1. protobuf基本编译

protobuf
编译通过
编译器protoc进行的,通过这个编译器,可以把.proto文件生成

go,Java,Python,C++, Ruby, JavaNano, Objective-C,或者C# 代码,生成命令如下:

protoc
–proto_path=
IMPORT_PATH
–go_out=
DST_DIR path/to/file.proto

  • go语言编译时,protobuf 编译器会把 .proto 文件编译成 .pd.go 文件

一般在使用的时候都是使用下面这种简单的命令

protoc --go_out=./ *.proto

然后这个 .proto 文件中添加一RPC服务,再次进行编译,发现生成的go文件没有发生变化,这是因为世界上的RPC实现有很多种,protoc编译器并不知道如何为HelloService服务生成代码,不过在protoc-gen-go内部已经集成了一个叫grpc插件,可以针对grpc生成代码

protoc --go_out=plugins=grpc:. *.proto
  1. protobuf 序列化反序列

(1).新建proto/test.proto

syntax = "proto3";
option go_package = "./protoService";
message Userinfo {
    string name = 1;
    int32 age = 2;
    repeated string hobby = 3;
    PhoneType phone=4;
}

//enum为关键字,作用为定义一种枚举类型
enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
}

(2).命令运行,生成.go文件

protoc --go_out=./ *.proto  //一般情况下使用这个命令
protoc --go_out=plugins=grpc:. *.proto  //有RPC服务的情况下使用这个命令

生成的.go文件如下图所示:

这里使用了google.golang.org/protobuf相关函数,则需要引入对应的插件进行操作,命令如下:

如果protoService/test.pd.go中的protobuf还是没有被引入,图示:

找到go mod tidy 下载的google.golang.org,把protobuf复制src下,如图示:

这样protoServe/test.pb.go中的goole相关插件就引入了,test.pb.go中的protobuf变绿,成功了:

main.go中实现序列化和反序列化

package main

import (
    "fmt"
    "go_code/micro/protoc/protoService"
    "google.golang.org/protobuf/proto"
)

func main() {
    //初始化赋值
    u := &protoService.Userinfo{
        Name: "zhangsan",
        Age: 20,
        Hobby: []string{"吃饭", "睡觉", "写代码"},
    }
    fmt.Println(u.GetHobby())
    // proto.Marshald对protoBufer进行序列化
    data, err1 := proto.Marshal(u)
    if err1 != nil {
        fmt.Println(err1)
    }
    fmt.Println(data)

    //proto.Unmarshal可以对protoBufer进行反序列化
    info := protoService.Userinfo{}
    err2 := proto.Unmarshal(data, &info)
    if err2 != nil {
        fmt.Println(err2)
    }

    fmt.Printf("%#v", info)
    fmt.Println(info.GetHobby())
}

效果如下图所示:

  1. protobuf案例演示

(1).案例1

userinfo.proto

用户信息相关proto:

使用了数据类型 string, int, repeated,enum等

syntax = "proto3";  //版本
//./userService:在./userService文件夹中生成文件
option go_package = "./userService";
//注意:写完一行以后要注意 ;
message userinfo{
    string username =1;  //类型 字段 = 数字(位置)
    int32 age =2;
    PhoneType type=3;
    repeated string hobby=4;
}

//enum为关键字,作用为定义一种枚举类型
enum PhoneType { 
    MOBILE = 0;
    HOME = 1; 
    WORK = 2; 
}

//编译的命令:protoc --go_out=./ *.proto
userService/userinfo.pd.go

使用:protoc –go_out=./ *.proto生成的.go文件

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//     protoc-gen-go v1.26.0
//     protoc        v3.20.0
// source: userinfo.proto

package userService

import (
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
    reflect "reflect"
    sync "sync"
)

const (
    // Verify that this generated code is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
    // Verify that runtime/protoimpl is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

//enum为关键字,作用为定义一种枚举类型
type PhoneType int32

const (
    PhoneType_MOBILE PhoneType = 0
    PhoneType_HOME   PhoneType = 1
    PhoneType_WORK   PhoneType = 2
)

// Enum value maps for PhoneType.
var (
    PhoneType_name = map[int32]string{
        0: "MOBILE",
        1: "HOME",
        2: "WORK",
    }
    PhoneType_value = map[string]int32{
        "MOBILE": 0,
        "HOME":   1,
        "WORK":   2,
    }
)

func (x PhoneType) Enum() *PhoneType {
    p := new(PhoneType)
    *p = x
    return p
}

func (x PhoneType) String() string {
    return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}

func (PhoneType) Descriptor() protoreflect.EnumDescriptor {
    return file_userinfo_proto_enumTypes[0].Descriptor()
}

func (PhoneType) Type() protoreflect.EnumType {
    return &file_userinfo_proto_enumTypes[0]
}

func (x PhoneType) Number() protoreflect.EnumNumber {
    return protoreflect.EnumNumber(x)
}

// Deprecated: Use PhoneType.Descriptor instead.
func (PhoneType) EnumDescriptor() ([]byte, []int) {
    return file_userinfo_proto_rawDescGZIP(), []int{0}
}

//注意:写完一行以后要注意 ;
type Userinfo struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Username string    `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
    Age      int32     `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
    Type     PhoneType `protobuf:"varint,3,opt,name=type,proto3,enum=PhoneType" json:"type,omitempty"`
    Hobby    []string  `protobuf:"bytes,4,rep,name=hobby,proto3" json:"hobby,omitempty"`
}

func (x *Userinfo) Reset() {
    *x = Userinfo{}
    if protoimpl.UnsafeEnabled {
        mi := &file_userinfo_proto_msgTypes[0]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *Userinfo) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*Userinfo) ProtoMessage() {}

func (x *Userinfo) ProtoReflect() protoreflect.Message {
    mi := &file_userinfo_proto_msgTypes[0]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use Userinfo.ProtoReflect.Descriptor instead.
func (*Userinfo) Descriptor() ([]byte, []int) {
    return file_userinfo_proto_rawDescGZIP(), []int{0}
}

func (x *Userinfo) GetUsername() string {
    if x != nil {
        return x.Username
    }
    return ""
}

func (x *Userinfo) GetAge() int32 {
    if x != nil {
        return x.Age
    }
    return 0
}

func (x *Userinfo) GetType() PhoneType {
    if x != nil {
        return x.Type
    }
    return PhoneType_MOBILE
}

func (x *Userinfo) GetHobby() []string {
    if x != nil {
        return x.Hobby
    }
    return nil
}

var File_userinfo_proto protoreflect.FileDescriptor

var file_userinfo_proto_rawDesc = []byte{
    0x0a, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
    0x22, 0x6e, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08,
    0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
    0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18,
    0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x74, 0x79,
    0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65,
    0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x68, 0x6f,
    0x62, 0x62, 0x79, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x68, 0x6f, 0x62, 0x62, 0x79,
    0x2a, 0x2b, 0x0a, 0x09, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a,
    0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d,
    0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x02, 0x42, 0x0f, 0x5a,
    0x0d, 0x2e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06,
    0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
    file_userinfo_proto_rawDescOnce sync.Once
    file_userinfo_proto_rawDescData = file_userinfo_proto_rawDesc
)

func file_userinfo_proto_rawDescGZIP() []byte {
    file_userinfo_proto_rawDescOnce.Do(func() {
        file_userinfo_proto_rawDescData = protoimpl.X.CompressGZIP(file_userinfo_proto_rawDescData)
    })
    return file_userinfo_proto_rawDescData
}

var file_userinfo_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_userinfo_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_userinfo_proto_goTypes = []interface{}{
    (PhoneType)(0),   // 0: PhoneType
    (*Userinfo)(nil), // 1: userinfo
}
var file_userinfo_proto_depIdxs = []int32{
    0, // 0: userinfo.type:type_name -> PhoneType
    1, // [1:1] is the sub-list for method output_type
    1, // [1:1] is the sub-list for method input_type
    1, // [1:1] is the sub-list for extension type_name
    1, // [1:1] is the sub-list for extension extendee
    0, // [0:1] is the sub-list for field type_name
}

func init() { file_userinfo_proto_init() }
func file_userinfo_proto_init() {
    if File_userinfo_proto != nil {
        return
    }
    if !protoimpl.UnsafeEnabled {
        file_userinfo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*Userinfo); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
        File: protoimpl.DescBuilder{
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: file_userinfo_proto_rawDesc,
            NumEnums:      1,
            NumMessages:   1,
            NumExtensions: 0,
            NumServices:   0,
        },
        GoTypes:           file_userinfo_proto_goTypes,
        DependencyIndexes: file_userinfo_proto_depIdxs,
        EnumInfos:         file_userinfo_proto_enumTypes,
        MessageInfos:      file_userinfo_proto_msgTypes,
    }.Build()
    File_userinfo_proto = out.File
    file_userinfo_proto_rawDesc = nil
    file_userinfo_proto_goTypes = nil
    file_userinfo_proto_depIdxs = nil
}
main.go

序列化
反序列化实现

package main

import (
    "fmt"
    "proto_deom/proto/userService"
    "google.golang.org/protobuf/proto"
)

func main() {
    u := &userService.Userinfo{
        Username: "张三",
        Age:      20,
        Hobby:    []string{"吃饭", "睡觉", "写代码"},
    }
    // fmt.Println(u)

    fmt.Println(u.GetType())
    fmt.Println(u.GetUsername())
    fmt.Println(u.GetHobby())
    //Protobuf的序列化
    data, _ := proto.Marshal(u)
    fmt.Println(data)

    //Protobuf的反序列化
    user := userService.Userinfo{}
    proto.Unmarshal(data, &user)
    fmt.Printf("%#vn", user)
    fmt.Println(user.GetHobby())
}

(2).案例2

order.proto

订单相关:

相关数据类型的使用,
message嵌套使用

syntax = "proto3";
option go_package = "./orderService";

message Order{   
    int64 id =1;
    double price =2;
    string name =3;
    string tel=4;
    string address=5;
    string addTime=6;
    //message可以嵌套
    // message OrderItem{
    //     int64 goodsId =1;
    //     string title=2;
    //     double price =3;
    //     int32 num =4;
    // }
    OrderItem Orderitem =7;
}

message OrderItem{
        int64 goodsId =1;
        string title=2;
        double price =3;
        int32 num =4;
}

//   protoc --go_out=./ *.proto
orderService/order.pb.go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//     protoc-gen-go v1.26.0
//     protoc        v3.20.0
// source: order.proto

package orderService

import (
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
    reflect "reflect"
    sync "sync"
)

const (
    // Verify that this generated code is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
    // Verify that runtime/protoimpl is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

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

    Id      int64   `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
    Price   float64 `protobuf:"fixed64,2,opt,name=price,proto3" json:"price,omitempty"`
    Name    string  `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
    Tel     string  `protobuf:"bytes,4,opt,name=tel,proto3" json:"tel,omitempty"`
    Address string  `protobuf:"bytes,5,opt,name=address,proto3" json:"address,omitempty"`
    AddTime string  `protobuf:"bytes,6,opt,name=addTime,proto3" json:"addTime,omitempty"`
    //message可以嵌套
    // message OrderItem{
    //     int64 goodsId =1;
    //     string title=2;
    //     double price =3;
    //     int32 num =4;
    // }
    Orderitem *OrderItem `protobuf:"bytes,7,opt,name=Orderitem,proto3" json:"Orderitem,omitempty"`
}

func (x *Order) Reset() {
    *x = Order{}
    if protoimpl.UnsafeEnabled {
        mi := &file_order_proto_msgTypes[0]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *Order) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*Order) ProtoMessage() {}

func (x *Order) ProtoReflect() protoreflect.Message {
    mi := &file_order_proto_msgTypes[0]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use Order.ProtoReflect.Descriptor instead.
func (*Order) Descriptor() ([]byte, []int) {
    return file_order_proto_rawDescGZIP(), []int{0}
}

func (x *Order) GetId() int64 {
    if x != nil {
        return x.Id
    }
    return 0
}

func (x *Order) GetPrice() float64 {
    if x != nil {
        return x.Price
    }
    return 0
}

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

func (x *Order) GetTel() string {
    if x != nil {
        return x.Tel
    }
    return ""
}

func (x *Order) GetAddress() string {
    if x != nil {
        return x.Address
    }
    return ""
}

func (x *Order) GetAddTime() string {
    if x != nil {
        return x.AddTime
    }
    return ""
}

func (x *Order) GetOrderitem() *OrderItem {
    if x != nil {
        return x.Orderitem
    }
    return nil
}

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

    GoodsId int64   `protobuf:"varint,1,opt,name=goodsId,proto3" json:"goodsId,omitempty"`
    Title   string  `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
    Price   float64 `protobuf:"fixed64,3,opt,name=price,proto3" json:"price,omitempty"`
    Num     int32   `protobuf:"varint,4,opt,name=num,proto3" json:"num,omitempty"`
}

func (x *OrderItem) Reset() {
    *x = OrderItem{}
    if protoimpl.UnsafeEnabled {
        mi := &file_order_proto_msgTypes[1]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *OrderItem) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*OrderItem) ProtoMessage() {}

func (x *OrderItem) ProtoReflect() protoreflect.Message {
    mi := &file_order_proto_msgTypes[1]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use OrderItem.ProtoReflect.Descriptor instead.
func (*OrderItem) Descriptor() ([]byte, []int) {
    return file_order_proto_rawDescGZIP(), []int{1}
}

func (x *OrderItem) GetGoodsId() int64 {
    if x != nil {
        return x.GoodsId
    }
    return 0
}

func (x *OrderItem) GetTitle() string {
    if x != nil {
        return x.Title
    }
    return ""
}

func (x *OrderItem) GetPrice() float64 {
    if x != nil {
        return x.Price
    }
    return 0
}

func (x *OrderItem) GetNum() int32 {
    if x != nil {
        return x.Num
    }
    return 0
}

var File_order_proto protoreflect.FileDescriptor

var file_order_proto_rawDesc = []byte{
    0x0a, 0x0b, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb1, 0x01,
    0x0a, 0x05, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
    0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65,
    0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a,
    0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
    0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
    0x74, 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05,
    0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a,
    0x07, 0x61, 0x64, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
    0x61, 0x64, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72,
    0x69, 0x74, 0x65, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x4f, 0x72, 0x64,
    0x65, 0x72, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x74, 0x65,
    0x6d, 0x22, 0x63, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x18,
    0x0a, 0x07, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
    0x07, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c,
    0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14,
    0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x70,
    0x72, 0x69, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28,
    0x05, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x42, 0x10, 0x5a, 0x0e, 0x2e, 0x2f, 0x6f, 0x72, 0x64, 0x65,
    0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
    file_order_proto_rawDescOnce sync.Once
    file_order_proto_rawDescData = file_order_proto_rawDesc
)

func file_order_proto_rawDescGZIP() []byte {
    file_order_proto_rawDescOnce.Do(func() {
        file_order_proto_rawDescData = protoimpl.X.CompressGZIP(file_order_proto_rawDescData)
    })
    return file_order_proto_rawDescData
}

var file_order_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_order_proto_goTypes = []interface{}{
    (*Order)(nil),     // 0: Order
    (*OrderItem)(nil), // 1: OrderItem
}
var file_order_proto_depIdxs = []int32{
    1, // 0: Order.Orderitem:type_name -> OrderItem
    1, // [1:1] is the sub-list for method output_type
    1, // [1:1] is the sub-list for method input_type
    1, // [1:1] is the sub-list for extension type_name
    1, // [1:1] is the sub-list for extension extendee
    0, // [0:1] is the sub-list for field type_name
}

func init() { file_order_proto_init() }
func file_order_proto_init() {
    if File_order_proto != nil {
        return
    }
    if !protoimpl.UnsafeEnabled {
        file_order_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*Order); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_order_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*OrderItem); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
        File: protoimpl.DescBuilder{
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: file_order_proto_rawDesc,
            NumEnums:      0,
            NumMessages:   2,
            NumExtensions: 0,
            NumServices:   0,
        },
        GoTypes:           file_order_proto_goTypes,
        DependencyIndexes: file_order_proto_depIdxs,
        MessageInfos:      file_order_proto_msgTypes,
    }.Build()
    File_order_proto = out.File
    file_order_proto_rawDesc = nil
    file_order_proto_goTypes = nil
    file_order_proto_depIdxs = nil
}

(3).案例3

goods.proto

RPC服务的定义

syntax = "proto3";
option go_package = "./goodsService";
//RPC接口, 定义RPC服务,生成的是接口
service GoodsService{
    rpc AddGoods(AddGoodsReq) returns (AddGoodsRes);
    rpc GetGoods(GetGoodsReq) returns (GetGoodsRes);
}
message GoodsMode{
    string title =1;
    double price =2;
    string content =3;
}
//AddGoods相关参数
message AddGoodsReq{
    GoodsMode params=1;
}
message AddGoodsRes{
    string message =1;
    bool success =2;    
}
//GetGoods相关参数
message GetGoodsReq{
    int32 id =1;    
}
message GetGoodsRes{
   repeated GoodsMode goodsList=1;
}
/*
    protoc --go_out=./ *.proto
    有RPC接口使用下面方法生成proto go文件   
    protoc --go_out=plugins=grpc:. *.proto
*/
goodsService/goods.pb.go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//     protoc-gen-go v1.26.0
//     protoc        v3.20.0
// source: goods.proto

package goodsService

import (
    context "context"
    grpc "google.golang.org/grpc"
    codes "google.golang.org/grpc/codes"
    status "google.golang.org/grpc/status"
    protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    protoimpl "google.golang.org/protobuf/runtime/protoimpl"
    reflect "reflect"
    sync "sync"
)

const (
    // Verify that this generated code is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
    // Verify that runtime/protoimpl is sufficiently up-to-date.
    _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

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

    Title   string  `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
    Price   float64 `protobuf:"fixed64,2,opt,name=price,proto3" json:"price,omitempty"`
    Content string  `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"`
}

func (x *AddGoodsReq) Reset() {
    *x = AddGoodsReq{}
    if protoimpl.UnsafeEnabled {
        mi := &file_goods_proto_msgTypes[0]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *AddGoodsReq) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*AddGoodsReq) ProtoMessage() {}

func (x *AddGoodsReq) ProtoReflect() protoreflect.Message {
    mi := &file_goods_proto_msgTypes[0]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use AddGoodsReq.ProtoReflect.Descriptor instead.
func (*AddGoodsReq) Descriptor() ([]byte, []int) {
    return file_goods_proto_rawDescGZIP(), []int{0}
}

func (x *AddGoodsReq) GetTitle() string {
    if x != nil {
        return x.Title
    }
    return ""
}

func (x *AddGoodsReq) GetPrice() float64 {
    if x != nil {
        return x.Price
    }
    return 0
}

func (x *AddGoodsReq) GetContent() string {
    if x != nil {
        return x.Content
    }
    return ""
}

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

    Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
    Success bool   `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"`
}

func (x *AddGoodsRes) Reset() {
    *x = AddGoodsRes{}
    if protoimpl.UnsafeEnabled {
        mi := &file_goods_proto_msgTypes[1]
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        ms.StoreMessageInfo(mi)
    }
}

func (x *AddGoodsRes) String() string {
    return protoimpl.X.MessageStringOf(x)
}

func (*AddGoodsRes) ProtoMessage() {}

func (x *AddGoodsRes) ProtoReflect() protoreflect.Message {
    mi := &file_goods_proto_msgTypes[1]
    if protoimpl.UnsafeEnabled && x != nil {
        ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
        if ms.LoadMessageInfo() == nil {
            ms.StoreMessageInfo(mi)
        }
        return ms
    }
    return mi.MessageOf(x)
}

// Deprecated: Use AddGoodsRes.ProtoReflect.Descriptor instead.
func (*AddGoodsRes) Descriptor() ([]byte, []int) {
    return file_goods_proto_rawDescGZIP(), []int{1}
}

func (x *AddGoodsRes) GetMessage() string {
    if x != nil {
        return x.Message
    }
    return ""
}

func (x *AddGoodsRes) GetSuccess() bool {
    if x != nil {
        return x.Success
    }
    return false
}

var File_goods_proto protoreflect.FileDescriptor

var file_goods_proto_rawDesc = []byte{
    0x0a, 0x0b, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a,
    0x0b, 0x41, 0x64, 0x64, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05,
    0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74,
    0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
    0x01, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74,
    0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
    0x6e, 0x74, 0x22, 0x41, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65,
    0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01,
    0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73,
    0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75,
    0x63, 0x63, 0x65, 0x73, 0x73, 0x32, 0x36, 0x0a, 0x0c, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x53, 0x65,
    0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x47, 0x6f, 0x6f, 0x64,
    0x73, 0x12, 0x0c, 0x2e, 0x41, 0x64, 0x64, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x1a,
    0x0c, 0x2e, 0x41, 0x64, 0x64, 0x47, 0x6f, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x42, 0x10, 0x5a,
    0x0e, 0x2e, 0x2f, 0x67, 0x6f, 0x6f, 0x64, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62,
    0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
    file_goods_proto_rawDescOnce sync.Once
    file_goods_proto_rawDescData = file_goods_proto_rawDesc
)

func file_goods_proto_rawDescGZIP() []byte {
    file_goods_proto_rawDescOnce.Do(func() {
        file_goods_proto_rawDescData = protoimpl.X.CompressGZIP(file_goods_proto_rawDescData)
    })
    return file_goods_proto_rawDescData
}

var file_goods_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_goods_proto_goTypes = []interface{}{
    (*AddGoodsReq)(nil), // 0: AddGoodsReq
    (*AddGoodsRes)(nil), // 1: AddGoodsRes
}
var file_goods_proto_depIdxs = []int32{
    0, // 0: GoodsService.AddGoods:input_type -> AddGoodsReq
    1, // 1: GoodsService.AddGoods:output_type -> AddGoodsRes
    1, // [1:2] is the sub-list for method output_type
    0, // [0:1] is the sub-list for method input_type
    0, // [0:0] is the sub-list for extension type_name
    0, // [0:0] is the sub-list for extension extendee
    0, // [0:0] is the sub-list for field type_name
}

func init() { file_goods_proto_init() }
func file_goods_proto_init() {
    if File_goods_proto != nil {
        return
    }
    if !protoimpl.UnsafeEnabled {
        file_goods_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*AddGoodsReq); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
        file_goods_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
            switch v := v.(*AddGoodsRes); i {
            case 0:
                return &v.state
            case 1:
                return &v.sizeCache
            case 2:
                return &v.unknownFields
            default:
                return nil
            }
        }
    }
    type x struct{}
    out := protoimpl.TypeBuilder{
        File: protoimpl.DescBuilder{
            GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
            RawDescriptor: file_goods_proto_rawDesc,
            NumEnums:      0,
            NumMessages:   2,
            NumExtensions: 0,
            NumServices:   1,
        },
        GoTypes:           file_goods_proto_goTypes,
        DependencyIndexes: file_goods_proto_depIdxs,
        MessageInfos:      file_goods_proto_msgTypes,
    }.Build()
    File_goods_proto = out.File
    file_goods_proto_rawDesc = nil
    file_goods_proto_goTypes = nil
    file_goods_proto_depIdxs = nil
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// GoodsServiceClient is the client API for GoodsService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type GoodsServiceClient interface {
    AddGoods(ctx context.Context, in *AddGoodsReq, opts ...grpc.CallOption) (*AddGoodsRes, error)
}

type goodsServiceClient struct {
    cc grpc.ClientConnInterface
}

func NewGoodsServiceClient(cc grpc.ClientConnInterface) GoodsServiceClient {
    return &goodsServiceClient{cc}
}

func (c *goodsServiceClient) AddGoods(ctx context.Context, in *AddGoodsReq, opts ...grpc.CallOption) (*AddGoodsRes, error) {
    out := new(AddGoodsRes)
    err := c.cc.Invoke(ctx, "/GoodsService/AddGoods", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

// GoodsServiceServer is the server API for GoodsService service.
type GoodsServiceServer interface {
    AddGoods(context.Context, *AddGoodsReq) (*AddGoodsRes, error)
}

// UnimplementedGoodsServiceServer can be embedded to have forward compatible implementations.
type UnimplementedGoodsServiceServer struct {
}

func (*UnimplementedGoodsServiceServer) AddGoods(context.Context, *AddGoodsReq) (*AddGoodsRes, error) {
    return nil, status.Errorf(codes.Unimplemented, "method AddGoods not implemented")
}

func RegisterGoodsServiceServer(s *grpc.Server, srv GoodsServiceServer) {
    s.RegisterService(&_GoodsService_serviceDesc, srv)
}

func _GoodsService_AddGoods_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(AddGoodsReq)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(GoodsServiceServer).AddGoods(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/GoodsService/AddGoods",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(GoodsServiceServer).AddGoods(ctx, req.(*AddGoodsReq))
    }
    return interceptor(ctx, in, info, handler)
}

var _GoodsService_serviceDesc = grpc.ServiceDesc{
    ServiceName: "GoodsService",
    HandlerType: (*GoodsServiceServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "AddGoods",
            Handler:    _GoodsService_AddGoods_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "goods.proto",
}

[上一节][golang 微服务] 2. RPC架构介绍以及通过RPC实现微服务

[下一节][golang 微服务] 4. gRPC介绍,Protobuf结合gRPC 创建微服务

原文地址:https://blog.csdn.net/zhoupenghui168/article/details/130923516

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_37020.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注