go微服务开山篇之protoBuf组件

   日期:2020-09-21     浏览:90    评论:0    
核心提示:文章目录protoBuf安装下载安装proto命令proto语法`message`类型定义方式说明:字段定义字段详细说明注释`enum`枚举类型定义方式字段定义service类型定义方式字段定义使用其他 Message 类型字段类型protoBuf组件小实战`proto`文件`proto`转go语言go使用转换过来的文件protoBuf安装下载安装下载地址:https://github.com/protocolbuffers/protobuf/releases根据系统下载对应的安装文件,我现在是

文章目录

  • protoBuf安装
    • 下载安装
    • proto命令
  • proto语法
    • message类型
      • 定义方式
      • 说明:
      • 字段定义
        • 字段详细说明
      • 注释
    • enum枚举类型
      • 定义方式
      • 字段定义
    • service类型
      • 定义方式
      • 字段定义
    • 使用其他 Message 类型
    • 字段类型
  • protoBuf组件小实战
    • proto文件
    • proto转go文件
    • go使用转换过来的文件

protoBuf安装

下载安装

  1. 下载地址:https://github.com/protocolbuffers/protobuf/releases

    根据系统下载对应的安装文件,我现在是win10就下载了protoc-3.13.0-win64.zip

  2. 解压文件,如:E:\protoc-3.13.0-win64

  3. 添加环境变量或者将bin目录下的protoc.exe拷贝到gopath下的bin文件夹中,不用添加环境变量

    1. 在系统变量中新建:变量名:PROTOBUF_HOME 变量值:E:\protoc-3.13.0-win64
    2. 在系统变量中,编辑path,将前面建的PROTOBUF_HOME下的添加进去%PROTOBUF_HOME%\bin;
    3. cmd中执行protoc --version查看版本,如果可以看到版本号,说明环境变量没问题
  4. 安装protoc-gen-go

    1. 下载:go get -u github.com/golang/protobuf/protoc-gen-go
    2. gopath的bin生成protoc-gen-go.exe

proto命令

# 查看版本信息
protoc --version

# 生成对应语言的文件: --go_out=. 这是生成golang文件 .代表当前目录 hello.proto文件名
protoc --go_out=. hello.proto
# 或者
protoc hello.proto --go_out=.

proto语法

hello.proto

// 版本
syntax = "proto3";


option go_package = ".;hello";
package hello;

// message:一种消息类型,后面会详细说明类型
message Hello{ 
  // optional默认会加可以不写,写了生成
  optional string name = 1;
  int32 age = 2;
  string addr = 3;
}

说明:message 表示messages消息类型,后面跟消息名称

message类型

定义方式

// message后面跟消息名称
message xxx{ 
}

说明:

  • .proto文件中定义多种messages类型如:message、enum 和 service
  • 一个.proto文件中可以定义多个messages类型,建议一个文件中不要出现多种类型,会导致依赖性膨胀

字段定义

message Hello{ 
  optional string name = 1;
  required int32 age = 2;
  repeated string addr = 3;
}

字段详细说明


optional string stringVal = 1;
1.字段规则:可以忽略,不用指定,默认为optional
	// optional 可以传或者不传值
    optional:字段可出现 0 次或1次,表示可选,为空可以指定默认值 [default = 10],不然使用语言的默认值
        optional int32 result_per_page = 3 [default = 10];
            字符串默认为空字符串
            数字默认为0
            bool默认为false
            枚举默认为第一个列出的值,一定要注意枚举的顺序,容易有坑
    // required 必须传值、而且只能传一次 注意proto3中已经无法使用required 
    required:字段只能也必须出现 1// repeated 可以传多个值或者不传值 
    repeated:字段可出现任意多次(包括 0),数组或列表要使用这种
2.类型:
    int32int64、sint32、sint64、string32-bit ....
3.字段名称:
    注意命名规范 
4.=后面的数字表示字段编号:
    0 ~ 536870911(除去 1900019999 之间的数字,预留的)


关于optional的说明:
对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,
消息中的其它字段正常处理。---因为optional字段的特性,
很多接口在升级版本中都把后来添加的字段都统一的设置为optional字段,
这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,
因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡

注释

// 单行注释
 多行注释

enum枚举类型

定义方式

enum EnumAllowingAlias { 
  option allow_alias = true; 
  UNKNOWN = 0;
  STARTED = 1;
  RUNNING = 1;
}

你可以通过为不同的枚举常量指定相同的值来定义别名。
为此,你需要将 allow_alias 选项设置为true,否则 protocol 编译器将在找到别名时生成错误消息。

enum EnumAllowingAlias { 
  option allow_alias = true;
  UNKNOWN = 0;
  STARTED = 1;
  RUNNING = 1;
}

enum EnumNotAllowingAlias { 
  UNKNOWN = 0;
  STARTED = 1;
}

字段定义

UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;

都是常量,没有类型申明

注意:message中可以嵌套enum类型,里层的字段编号和外层的字段编号不冲突

service类型

定义方式

service TestService { 
    //rpc 服务端对外的函数名(传入参数)returns(返回参数)
    rpc SayHello (HelloRequest) returns (HelloReply) { }
}

message HelloRequest { 
  string name = 1;
}

message HelloReply { 
  string message = 1;
}

字段定义

rpc SayHello (HelloRequest) returns (HelloReply) { }
//rpc 服务端对外的函数名 (传入参数) returns (返回参数){}

使用其他 Message 类型

message后面的名称可以在其他的类型中使用,这个时候类型就是指定的类型了

message SearchResponse {
  repeated Result result = 1;   // 这里的类型是下面定的Result类型,包含 Result message的所有
}

message Result {
  required string url = 1;
  optional string title = 2;
  repeated string snippets = 3;
}

字段类型

.proto 说明 Go语言 C++语言 Python语言 Java语言
double 浮点类型 float64 double float double
float 浮点类型 float32 float float float
int32 int32 int32 int int
int64 int64 int64 int/long long
uint32 uint32 uint32 int/long int
uint64 uint64 uint64 int/long long
sint32 int32 int32 int int
sint64 int64 int64 int/long long
fixed32 uint32 uint32 int/long int
fixed64 uint64 uint64 int/long long
sfixed32 int32 int32 int int
sfixed34 int64 int64 int/long long
bool bool bool bool boolean
string string string str/unicode String
bytes []byte string str ByteString

protoBuf组件小实战

proto文件

E:\workspace\src\sample\protoBuf_sample\hello.proto

syntax = "proto3";
option go_package = ".;hello";
package hello;

message Hello{ 
  optional string name = 1;
  int32 age = 2;
  repeated string addr = 3;
}

proto转go文件

E:\workspace\src\sample\protoBuf_sample 到这个目录执行命令

// 因为proto文件中有设置optional,转换就需要加--experimental_allow_proto3_optional参数
protoc --go_out=. hello.proto --experimental_allow_proto3_optional

go使用转换过来的文件

这是proto文件生成的
E:\workspace\src\sample\protoBuf_sample\hello.pb.go

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.23.0
// protoc v3.13.0
// source: hello.proto

package hello

import (
	proto "github.com/golang/protobuf/proto"
	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)
)

// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4

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

	Name *string  `protobuf:"bytes,1,opt,name=name,proto3,oneof" json:"name,omitempty"`
	Age  int32    `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
	Addr []string `protobuf:"bytes,3,rep,name=addr,proto3" json:"addr,omitempty"`
}

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

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

func (*Hello) ProtoMessage() { }

func (x *Hello) ProtoReflect() protoreflect.Message { 
	mi := &file_hello_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 Hello.ProtoReflect.Descriptor instead.
func (*Hello) Descriptor() ([]byte, []int) { 
	return file_hello_proto_rawDescGZIP(), []int{ 0}
}

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

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

func (x *Hello) GetAddr() []string { 
	if x != nil { 
		return x.Addr
	}
	return nil
}

var File_hello_proto protoreflect.FileDescriptor

var file_hello_proto_rawDesc = []byte{ 
	0x0a, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x68,
	0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x4f, 0x0a, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x17, 0x0a,
	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e,
	0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20,
	0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72,
	0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x42, 0x07, 0x0a, 0x05,
	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
	file_hello_proto_rawDescOnce sync.Once
	file_hello_proto_rawDescData = file_hello_proto_rawDesc
)

func file_hello_proto_rawDescGZIP() []byte { 
	file_hello_proto_rawDescOnce.Do(func() { 
		file_hello_proto_rawDescData = protoimpl.X.CompressGZIP(file_hello_proto_rawDescData)
	})
	return file_hello_proto_rawDescData
}

var file_hello_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_hello_proto_goTypes = []interface{ }{ 
	(*Hello)(nil), // 0: hello.Hello
}
var file_hello_proto_depIdxs = []int32{ 
	0, // [0:0] is the sub-list for method output_type
	0, // [0:0] 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_hello_proto_init() }
func file_hello_proto_init() { 
	if File_hello_proto != nil { 
		return
	}
	if !protoimpl.UnsafeEnabled { 
		file_hello_proto_msgTypes[0].Exporter = func(v interface{ }, i int) interface{ } { 
			switch v := v.(*Hello); i { 
			case 0:
				return &v.state
			case 1:
				return &v.sizeCache
			case 2:
				return &v.unknownFields
			default:
				return nil
			}
		}
	}
	file_hello_proto_msgTypes[0].OneofWrappers = []interface{ }{ }
	type x struct{ }
	out := protoimpl.TypeBuilder{ 
		File: protoimpl.DescBuilder{ 
			GoPackagePath: reflect.TypeOf(x{ }).PkgPath(),
			RawDescriptor: file_hello_proto_rawDesc,
			NumEnums:      0,
			NumMessages:   1,
			NumExtensions: 0,
			NumServices:   0,
		},
		GoTypes:           file_hello_proto_goTypes,
		DependencyIndexes: file_hello_proto_depIdxs,
		MessageInfos:      file_hello_proto_msgTypes,
	}.Build()
	File_hello_proto = out.File
	file_hello_proto_rawDesc = nil
	file_hello_proto_goTypes = nil
	file_hello_proto_depIdxs = nil
}

E:\workspace\src\sample\main.go

package main

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	hello "sample/protoBuf_sample"
)

func main() { 
	name := "张三"
	data := &hello.Hello{ 
		// Name *string 这是因为proto中设置optional
		Name: &name,
		Age:  18,
		Addr: []string{ "北京", "上海", "广州"},
	}
	fmt.Println(data)

	// 编码
	byte_data, _ := proto.Marshal(data)
	//fmt.Println(byte_data)
	fmt.Printf("编码:%v\n", byte_data)

	var newData hello.Hello
	// 解码
	proto.Unmarshal(byte_data, &newData)
	fmt.Printf("解码:%v", newData)

	fmt.Println(newData.Name) //返回一个地址
	// 获取值
	fmt.Println(*newData.Name)
	fmt.Println(newData.GetName())

	// 将struct转换为字符串
	fmt.Println(newData.String())

	// Reset()会将struct的所有field的值清零
	//fmt.Println(newData.Reset)
}


 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服