Golang 语言 gRPC 使用的接口设计语言 protobuf

简介: Golang 语言 gRPC 使用的接口设计语言 protobuf

介绍

在学习 gRPC 之前,我们需要先了解 Protocal Buffers,也就是 protobuf,它是接口设计语言(IDL),它与编程语言无关,可以生成所有主流编程语言的代码,而且,它是二进制格式的数据,比较适合传递大量的数据。

在编写 gRPC 代码之前,首先使用 protobuf 定义服务端和客户端之间传递的消息(message)和 gRPC 服务(service),然后安装需要用到的库,使用命令行工具自动生成 gRPC 的代码。

protobuf 语法

protobuf 文件是以 .proto 后缀名结尾,一般会在文件开头声明 proto 的版本,syntax = "proto3";,如果不声明,则默认使用 proto2 版本。

接下来,我们就可以开始定义消息(message),使用关键字 messagemessage User {},然后在大括号中定义字段。

示例代码:

message User {
  int64 id = 1;
  string name = 2;
}

阅读上面这段代码,我们发现定义字段的格式是数据类型,字段名和编号(tag),tag 可以使用的数字范围是 1~536,870,911,但是不能使用 19000~19999 之间的数字,这部分数字是保留编号。

另外,编号 1~15 占用 1 个字节,所以建议用在使用频繁的字段上,编号 16~2047 占用 2 个字节,建议用在使用不频繁的字段上。

03

protobuf 数据类型

protobuf 数据类型包含标量类型和复合类型,其中标量类型包含以下几种:

  • 数值,包含 doublefloatint32int64uint32uint64sint32sint64fixed32fixed64sfixed32sfixed64
  • 尔 bool
  • 字符串 string
  • 字节 bytes

04

protobuf 字段规则

protobuf 字段规则有两个,单数(singular)和复数(repeated),必须满足其中一个,proto3 默认字段规则是单数。单数的意思是该字段只能出现 0 或 1 次,也可以理解为可选字段,如果出现 0 次,该字段的值是类型零值;复数是包含该字段类型任意数量元素的数组,在 Golang 中是该字段类型的切片。

示例代码:

message User {
  int64 id = 1;
  string name = 2;
  repeated string emails = 3;
}

05

protobuf 字段变更

在应用程序开发中,可能会遇到字段修改或删除,protobuf 不允许修改字段的编号(tag),但是可以删除字段,前提是被删除的字段的编号不再被其他字段使用,一般有两种方式,一种是在需要删除的字段名前添加前缀 OBSOLETE_,而不是删除该字段;另一种方式是把需要删除的字段的编号(tag)使用关键字 reserved 保留,避免被其他字段使用被删除字段的编号(tag)。

关键字 reserved 除了可以保留字段编号之外,还可以保留字段名称,可用于设置禁用字段名。

示例代码:

message User {
  int64 id = 1;
  string name = 2;
  // repeated string emails = 3;
  reserved 3, 16 to 100, 200 to max;
  reserved "uid", "uname";
}

06

protobuf 定义包名

在应用程序开发中,多个 proto 文件可能会存在相同的消息(message),我们可以使用包名做区分。

示例代码:

// 定义包名
package user;
// 定义 golang 包名
option go_package = "userpb";

07

protobuf 嵌套和导入

如果定义的 message 包含一些可以复用的字段,我们可以使用嵌套的方式,将可被复用的字段单独定义为 message,然后嵌套在需要使用它的 message 中,而且,还可以将可被复用的字段在单独的一个文件中定义 message,然后使用关键字 import 导入该文件。

示例代码:

// 导入
import "enum.proto";
message User {
  int64 id = 1;
  string name = 2;
  Gender gender = 4;
}

08

protoc 编译器

我们需要安装 protoc 编译器,编译我们编写的 proto 文件,生成指定编程语言的代码。

protoc 命令选项:

# 指定 proto 文件的目录
-IPATH, --proto_path=PATH
# 指定 go 文件输出目录
--go_out=dir_name

使用 protoc 编译 proto 文件,生成 golang 代码,需要安装一个包,go get -u github.com/golang/protobuf/protoc-gen-go

示例代码:

protoc --proto_path dir_name/ --go_out=dir_name/ dir_name/xx.proto

09

总结

本文我们介绍 gRPC 使用的接口设计语言 protobuf,需要注意的是 proto 文件中字段的编号必须保证唯一,使用 protoc 编译器编译 proto 文件生成指定编程语言的代码,protoc 原生不支持生成 golang 代码,需要安装一个包。

protoc 编译 proto 文件生成的指定编程语言的代码不可以直接修改,如果需要修改,可以修改 proto 文件,然后使用 protoc 重新编译。

限于篇幅,本文无法介绍 protobuf 的全部内容,关于 protobuf 的更多内容,比如枚举,map 等,建议感兴趣的读者朋友们阅读官方文档。

推荐阅读:

gRPC 初探与简单使用

Go 语言中的 gRPC 基础入门

参考资料:

https://developers.google.com/protocol-buffers/docs/proto3


目录
相关文章
|
4天前
|
安全 Go
Golang深入浅出之-Go语言模板(text/template):动态生成HTML
【4月更文挑战第24天】Go语言标准库中的`text/template`包用于动态生成HTML和文本,但不熟悉其用法可能导致错误。本文探讨了三个常见问题:1) 忽视模板执行错误,应确保正确处理错误;2) 忽视模板安全,应使用`html/template`包防止XSS攻击;3) 模板结构不合理,应合理组织模板以提高可维护性。理解并运用这些最佳实践,能提升Go语言模板编程的效率和安全性,助力构建稳健的Web应用。
16 0
|
23小时前
|
安全 测试技术 Go
Golang深入浅出之-Go语言单元测试与基准测试:testing包详解
【4月更文挑战第27天】Go语言的`testing`包是单元测试和基准测试的核心,简化了测试流程并鼓励编写高质量测试代码。本文介绍了测试文件命名规范、常用断言方法,以及如何进行基准测试。同时,讨论了测试中常见的问题,如状态干扰、并发同步、依赖外部服务和测试覆盖率低,并提出了相应的避免策略,包括使用`t.Cleanup`、`t.Parallel()`、模拟对象和检查覆盖率。良好的测试实践能提升代码质量和项目稳定性。
6 1
|
23小时前
|
运维 监控 Go
Golang深入浅出之-Go语言中的日志记录:log与logrus库
【4月更文挑战第27天】本文比较了Go语言中标准库`log`与第三方库`logrus`的日志功能。`log`简单但不支持日志级别配置和多样化格式,而`logrus`提供更丰富的功能,如日志级别控制、自定义格式和钩子。文章指出了使用`logrus`时可能遇到的问题,如全局logger滥用、日志级别设置不当和过度依赖字段,并给出了避免错误的建议,强调理解日志级别、合理利用结构化日志、模块化日志管理和定期审查日志配置的重要性。通过这些实践,开发者能提高应用监控和故障排查能力。
8 1
|
23小时前
|
安全 Go
Golang深入浅出之-Go语言标准库中的文件读写:io/ioutil包
【4月更文挑战第27天】Go语言的`io/ioutil`包提供简单文件读写,适合小文件操作。本文聚焦`ReadFile`和`WriteFile`函数,讨论错误处理、文件权限、大文件处理和编码问题。避免错误的关键在于检查错误、设置合适权限、采用流式读写及处理编码。遵循这些最佳实践能提升代码稳定性。
5 0
|
1天前
|
安全 Unix Go
Golang深入浅出之-Go语言中的时间与日期处理:time包详解
【4月更文挑战第26天】Go语言的`time`包提供处理日期和时间的功能,包括`time.Time`类型、时间戳、格式化与解析。本文讨论了核心概念、常见问题(如时区处理、格式字符串混淆、超时控制和并发安全)及解决方法。推荐使用`time.LoadLocation`管理时区,熟悉时间格式规则,用`context`精确控制超时,并注意并发安全。文中通过代码示例展示了如何获取格式化时间、计算时间差以及创建定时任务。学习和应用这些知识可提高程序的健壮性和准确性。
15 2
|
1天前
|
XML JSON Go
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
【4月更文挑战第26天】Go语言的`encoding/xml`库提供XML处理,包括序列化和反序列化。本文讨论了XML处理的基础,如`xml.Marshal`和`xml.Unmarshal`函数,以及常见问题和易错点,如标签命名、结构体嵌套、omitempty标签和命名空间。建议遵循标签命名规则,正确处理嵌套和属性,谨慎使用omitempty,以及理解并有效利用命名空间。文中还给出了基础示例和处理XML属性的代码示例,帮助读者掌握XML处理技巧。
12 1
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
|
1天前
|
JSON JavaScript 前端开发
Golang深入浅出之-Go语言JSON处理:编码与解码实战
【4月更文挑战第26天】本文探讨了Go语言中处理JSON的常见问题及解决策略。通过`json.Marshal`和`json.Unmarshal`进行编码和解码,同时指出结构体标签、时间处理、omitempty使用及数组/切片区别等易错点。建议正确使用结构体标签,自定义处理`time.Time`,明智选择omitempty,并理解数组与切片差异。文中提供基础示例及时间类型处理的实战代码,帮助读者掌握JSON操作。
13 1
Golang深入浅出之-Go语言JSON处理:编码与解码实战
|
1天前
|
安全 Go 开发者
Golang深入浅出之-Go语言模板(text/template):动态生成HTML
【4月更文挑战第25天】Go语言的`text/template`和`html/template`库提供动态HTML生成。本文介绍了模板基础,如基本语法和数据绑定,以及常见问题和易错点,如忘记转义、未初始化变量、复杂逻辑处理和错误处理。建议使用`html/template`防止XSS攻击,初始化数据结构,分离业务逻辑,并严谨处理错误。示例展示了条件判断和循环结构。通过遵循最佳实践,开发者能更安全、高效地生成HTML。
8 0
|
3天前
|
中间件 Go API
Golang深入浅出之-Go语言标准库net/http:构建Web服务器
【4月更文挑战第25天】Go语言的`net/http`包是构建高性能Web服务器的核心,提供创建服务器和发起请求的功能。本文讨论了使用中的常见问题和解决方案,包括:使用第三方路由库改进路由设计、引入中间件处理通用逻辑、设置合适的超时和连接管理以防止资源泄露。通过基础服务器和中间件的代码示例,展示了如何有效运用`net/http`包。掌握这些最佳实践,有助于开发出高效、易维护的Web服务。
15 1
|
3天前
|
数据管理 Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第25天】Go语言中的`context`包在并发、网络请求和长任务中至关重要,提供取消、截止时间和元数据管理。本文探讨`context`基础,如`Background()`、`TODO()`、`WithCancel()`、`WithDeadline()`和`WithTimeout()`。常见问题包括不当传递、过度使用`Background()`和`TODO()`以及忽略错误处理。通过取消和超时示例,强调正确传递上下文、处理取消错误和设置超时以提高应用健壮性和响应性。正确使用`context`是构建稳定高效Go应用的关键。
12 1