一、protobuf语言基础
1、.proto文件
- 创建.proto文件时,文件命名应该使用全小写字母命名;多个字母之间_连接。例如:lower_snake_case.proto。
- 书写.proto文件代码时,应使用2个空格的缩进。
- 注释方式:单行使用“//”或者多行使用“/**/”。
syntax = "proto3";
package user;
import "google/protobuf/empty.proto";
// delete user
message DeleteUserRequest {
string uid = 1;
}
service User {
rpc delete_user(DeleteUserRequest) returns (google.protobuf.Empty);
}
标准的proto文件就像这份示例文件一样可以分为三部分, 第一部分是前三行,这部分是proto文件的声明区,其中第一行标明当前proto文件的语法是proto3(没有特别说明,本文所介绍的语法都是proto3),第二行表示该文件的包名为user,这样会方便别的文件引入这个文件的定义,第三行表示导入empty.proto
文件,接下来在这个文件都可以使用empty.proto
文件定义的东西。
第二部分是5-8行, 这部分是消息体区, 这里定义了一个名为DeleteUserRequest
的消息体,这个消息体中定义了一个名为uid的字段,且它的类型是string
,字段排序是1。在实际开发中,大部分的变动都是在这一部分中发生, 且需要关注的点比较多。
第三部分是11-13行,这部分是服务定义区, 这里定义了一个名为User
的服务,该服务中有一个名为delete_user
的方法,且该方法接受的请求是DeleteUserRequest
消息体,响应的是Empty
消息体。可以简单的理解为这部分是定义一个类, 同时为每个类定义一些方法,而这些方法只拥有函数签名,没有具体实现。
了解完了Proto文件结构后,可以开始了解Protobuf语法。
2、Protobuf语法
2.1 字段编号
在编写消息体时, 最重要的一点就是字段编号, 从前面的说明可以看出, Protobuf的序列化是通过字段编号进行翻译的,所以我们要保证字段编号和字段是一一对应的, 一般的情况下我们都要遵循字段编号从1开始逐渐递增, 比如下面这个消息体:
message DemoRequest {
string uid = 1;
string mobile = 2;
int32 age = 3;
}
它的字段编号都是逐渐递增的,后面在新增字段时也要按照递增的方法指定字段编号,绝不能复用之前曾经存在的字段编号,即使是把某个字段进行重构,比如把上述的消息体进行更改:
// 通常不删除已经使用的字段, 这里只做演示
message DemoRequest {
string uid = 1;
string mobile = 2;
int32 brithday = 4; // 统一使用时间戳表示日期
}
虽然更改后的消息体里面的age字段被brithday替换了, 但是brithday的字段编号还是递增了1,这样做是可以防止旧版本客户端在没更随服务端变动时造成数据解析异常。
2.2 如何使用
在Protobuf的消息体中,每个字段的类型都是固定的, 因为传输固定的类型才能减少传输资源的占用,所以我们在定义消息体的字段时,一定要结合业务需求来定义字段的类型, 以下是一个常见的Protobuf基础字段类型与Python类型的对照表:
需要注意的是,我们虽然声明的字段没有标明他的值是多少,但是他们都有默认值:
- 字符串类型:空字符串
- 字节类型:空字节
- 数字类型: 0
- enum: 默认值的第一个元素,且值必须为0
此外, Protobuf还支持定义其它类型,这些类型具有跟Python等价类型的用法,但是在使用的时候还是有些区别,例如:
- Timestamp是Protobuf中的时间类型,在Python代码中,可以通过语法
ToDatetime
转为datetime。 - Repeated 可以使该字段表重复任意次数,就像Python的Sequence对象,但是实际上可以认为是Python的List对象。
等等......感兴趣可以参考以下文章:
Python-gRPC实践(2)--Protocol Buffer - 知乎
二、接口设置示例操作
-
DX Mesh编写protobuf和RPC接口
首先,创建一个TryService的文件夹,进入该文件夹,运行以下命令初始化TryService的工程:
xbuilder new -n TryService
DX Mesh会自动生成一个source_api_0_0_1.proto的文件:
-
运行以下代码进行工程语言初始化,DX Mesh目前支持Python和Rust两种编程语言,这里用的是Python语言:
(注意下面的是"-l",而不是"-1")
xbuilder init -l py
-
可以看到生成了src文件,进行接口功能编写只需要关注于src\service.py文件即可:
-
编辑好service.py文件后,接下来运行以下命令对工程进行打包:
xbuilder pack
-
接下来运行以下命令把工程安装到xport服务上:
(注意下面的“D:\DX-Mesh\xport”是xport.exe所在路径)
xbuilder install -x D:\DX-Mesh\xport
-
接下来修改xport\dxmesh.toml的配置文件,这里用127.0.0.1:8090ip端口(监听端)监听127.0.0.1:8091ip端口(服务端):
-
启动xport,查看XComService_0_0_1工程和TryService_0_0_1工程是否被成功启动。
-
最后使用postman进行TryService_0_0_1工程的接口测试。
Nothing comes from nothing.