grpc传输大量数据python_gRPC【RPC自定义http2.0协议传输】

gRPC是一个高性能、开源的RPC框架,支持多种语言和平台。它使用ProtocolBuffers(proto3)作为消息协议,利用HTTP/2进行传输。ProtocolBuffers是一种结构化数据序列化机制,可用于多种语言的数据交换。在gRPC中,服务通过.proto文件定义,编译后生成服务器和客户端代码。此外,ProtocolBuffers支持消息类型、枚举、映射、oneof等特性。
摘要由CSDN通过智能技术生成

gRPC

简介

gRPC是由Google公司开源的高性能RPC框架。

gRPC支持多语言

gRPC原生使用C、Java、Go进行了三种实现,而C语言实现的版本进行封装后又支持C++、C#、Node、ObjC、 Python、Ruby、PHP等开发语言

gRPC支持多平台

支持的平台包括:Linux、Android、iOS、MacOS、Windows

gRPC的消息协议使用Google自家开源的Protocol Buffers协议机制(proto3) 序列化

gRPC的传输使用HTTP/2标准,支持双向流和连接多路复用

架构

C语言实现的gRPC支持多语言,其架构如下

使用方法

安装

pip install grpc

pipinstall grpcio-tools

使用

使用Protocol Buffers(proto3)的IDL接口定义语言定义接口服务,编写在文本文件(以.proto为后缀名)中。

使用protobuf编译器生成服务器和客户端使用的stub代码

编写补充服务器和客户端逻辑代码

Protocol Buffers

Protocol Buffers 是一种与语言无关,平台无关的可扩展机制,用于序列化结构化数据。使用Protocol Buffers 可以一次定义结构化的数据,然后可以使用特殊生成的源代码轻松地在各种数据流中使用各种语言编写和读取结构化数据。

现在有许多框架等在使用Protocol Buffers。gRPC也是基于Protocol Buffers。 Protocol Buffers 目前有2和3两个版本号。

在gRPC中推荐使用proto3版本。

1 文档结构

1) Protocol Buffers版本

Protocol Buffers文档的第一行非注释行,为版本申明,不填写的话默认为版本2。

syntax = "proto3"; 或者 syntax = "proto2";

2)Package包

Protocol Buffers 可以声明package,来防止命名冲突。 Packages是可选的。

package foo.bar; message Open { ... }

使用的时候,也要加上命名空间,

message Foo { ... foo.bar.Open open = 1; ... }

注意:对于Python而言,package会被忽略处理,因为Python中的包是以文件目录来定义的。

3)导入

Protocol Buffers 中可以导入其它文件消息等,与Python的import类似。

import “myproject/other_protos.proto”;

4)定义各种消息和服务

消息messge是用来定义数据的,服务service是用来gRPC的方法的。

2 注释

Protocol Buffers 提供以下两种注释方式。

// 单行注释 /* 多行注释 多行注释 */

3 数据类型

3.1 基本数据类型

.proto

说明

Python

double

float

float

float

int32

使用变长编码,对负数编码效率低, 如果你的变量可能是负数,可以使用sint32

int

int64

使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint64

int/long

uint32

使用变长编码

int/long

uint64

使用变长编码

int/long

sint32

使用变长编码,带符号的int类型,对负数编码比int32高效

int

sint64

使用变长编码,带符号的int类型,对负数编码比int64高效

int/long

fixed32

4字节编码, 如果变量经常大于2^{28} 的话,会比uint32高效

int

fixed64

8字节编码, 如果变量经常大于2^{56} 的话,会比uint64高效

int/long

sfixed32

4字节编码

int

sfixed64

8字节编码

int/long

bool

bool

string

必须包含utf-8编码或者7-bit ASCII text

str

bytes

任意的字节序列

str

3.2 枚举

在 Proto Buffers 中,我们可以定义枚举和枚举类型,

enum Corpus{ UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4;

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

定义枚举的时候,我们要保证第一个枚举值必须是0,枚举值不能重复,除非使用 option allow_alias = true 选项来开启别名。

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

枚举值的范围是32-bit integer,但因为枚举值使用变长编码,所以不推荐使用负数作为枚举值,因为这会带来效率问题。

4 消息类型

Protocol Buffers使用message定义消息数据。在Protocol Buffers中使用的数据都是通过message消息数据封装基本类型数据或其他消息数据,对应Python中的类。

message SearchRequest{ string query = 1; int32 page_number = 2; int32 result_per_page = 3; }

4.1 字段编号

消息定义中的每个字段都有唯一的编号。这些字段编号用于以消息二进制格式标识字段,并且在使用消息类型后不应更改。 请注意,1到15范围内的字段编号需要一个字节进行编码,包括字段编号和字段类型。16到2047范围内的字段编号占用两个字节。因此,您应该为非常频繁出现的消息元素保留数字1到15。请记住为将来可能添加的常用元素留出一些空间。

最小的标识号可以从1开始,最大到2^29 - 1,或 536,870,911。不可以使用其中的[19000-19999]的标识号, Protobuf协议实现中对这些进行了预留。如果非要在.proto文件中使用这些预留标识号,编译时就会报警。同样你也不能使用早期保留的标识号。

4.2 指定字段规则

消息字段可以是以下之一:

singular:格式良好的消息可以包含该字段中的零个或一个(但不超过一个)。

repeated:此字段可以在格式良好的消息中重复任意次数(包括零)。将保留重复值的顺序。对应Python的列表。 message Result{ string url = 1; string title = 2; repeated string snippets = 3; }

4.3 添加更多消息类型

可以在单个.proto文件中定义多个消息类型。

message SearchRequest{ string query = 1; int32 page_number = 2; int32 result_per_page = 3; } message SearchResponse{ ... }

4.4 保留字段

保留变量不被使用

如果通过完全删除字段或将其注释来更新消息类型,则未来用户可以在对类型进行自己的更新时重用字段编号。如果以后加载相同的旧版本,这可能会导致严重问题,包括数据损坏,隐私错误等。确保不会发生这种情况的一种方法是指定已删除字段的字段编号(或名称)reserved。如果将来的任何用户尝试使用这些字段标识符,protobuf编译器将会报错。

message Foo{ reserved 2, 15, 9 to 11; reserved "foo", "bar"; }

4.5 默认值

解析消息时,如果编码消息不包含特定的单数元素,则解析对象中的相应字段将设置为该字段的默认值。这些默认值是特定于类型的:

对于字符串,默认值为空字符串。

对于字节,默认值为空字节。

对于bools,默认值为false。

对于数字类型,默认值为零。

对于枚举,默认值是第一个定义的枚举值,该值必须为0。

对于消息字段,未设置该字段。它的确切值取决于语言。

重复字段的默认值为空(通常是相应语言的空列表)。

4.6 嵌套类型

你可以在其他消息类型中定义、使用消息类型,在下面的例子中,Result消息就定义在SearchResponse消息内,如:

message SearchResponse{ message Result{ string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; }

如果要在其父消息类型之外重用此消息类型,使用

SearchResponse.Result

5 map映射

如果要在数据定义中创建关联映射,Protocol Buffers提供了一种方便的语法:

map< key_type, value_type> map_field = N ;

其中key_type可以是任何整数或字符串类型。请注意,枚举不是有效的key_type。value_type可以是除map映射类型外的任何类型。

例如,如果要创建项目映射,其中每条Project消息都与字符串键相关联,则可以像下面这样定义它:

map projects = 3 ;

map的字段可以是repeated。

序列化后的顺序和map迭代器的顺序是不确定的,所以你不要期望以固定顺序处理map

当为.proto文件产生生成文本格式的时候,map会按照key 的顺序排序,数值化的key会按照数值排序。

从序列化中解析或者融合时,如果有重复的key则后一个key不会被使用,当从文本格式中解析map时,如果存在重复的key,则解析可能会失败。

如果为映射字段提供键但没有值,则字段序列化时的行为取决于语言。在Python中,使用类型的默认值。

6 oneof

如果你的消息中有很多可选字段, 并且同时至多一个字段会被设置, 你可以加强这个行为,使用oneof特性节省内存。

为了在.proto定义oneof字段, 你需要在名字前面加上oneof关键字, 比如下面例子的test_oneof:

message SampleMessage{ oneof test_oneof { string name = 4; SubMessage sub_message = 9; } }

然后你可以增加oneof字段到 oneof 定义中. 你可以增加任意类型的字段, 但是不能使用repeated 关键字。

7 定义服务

Protocol Buffers使用service定义RPC服务。

示例:

message HelloRequest { string greeting = 1; } message HelloResponse { string reply = 1; } service HelloService { rpc SayHello (HelloRequest) returns (HelloResponse) {} }

syntax = "proto3";

message UserRequest {

string user_id=1;

int32 channel_id=2;

int32 article_num=3;

int64 time_stamp=4;

}

message Track {

string click=1;

string collect=2;

string share=3;

string read=4;

}

message Article {

int64 article_id=1;

Track track=2;

}

message ArticleResponse {

string exposure=1;

int64 time_stamp=2;

repeated Article recommends=3;

}

service UserRecommend {

rpc user_recommend(UserRequest) returns(ArticleResponse) {}

}

代码生成

编译生成代码

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. reco.proto

-I表示搜索proto文件中被导入文件的目录

--python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的数据类型

--grpc_python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的服务类型

在toutiao-backend/common/rpc目录下执行上述命令,会自动生成如下两个rpc调用辅助代码模块:

reco_pb2.py 保存根据接口定义文件中的数据类型生成的python类

reco_pb2_grpc.py 保存根据接口定义文件中的服务方法类型生成的python调用RPC方法

原文出处:https://www.cnblogs.com/LiuXinyu12378/p/11336669.html

以下是在 Python 环境下配置 gRPC 的步骤: 1. 安装 gRPC 和 protobuf ``` pip install grpcio pip install grpcio-tools pip install protobuf ``` 2. 编写 .proto 文件 这里以一个简单的示例为例: ``` syntax = "proto3"; message HelloRequest { string name = 1; } message HelloResponse { string message = 1; } service HelloService { rpc SayHello (HelloRequest) returns (HelloResponse) {} } ``` 3. 生成 Python 代码 在命令行中运行以下命令: ``` python -m grpc_tools.protoc -I./protos --python_out=. --grpc_python_out=. ./protos/hello.proto ``` 其中,`./protos/hello.proto` 是你编写的 .proto 文件路径,`--python_out` 参数表示生成的 Python 代码输出路径,`--grpc_python_out` 表示生成的 gRPC Python 代码输出路径。 4. 编写 gRPC 服务端代码 ```python import grpc from concurrent import futures import time import hello_pb2 import hello_pb2_grpc class HelloServicer(hello_pb2_grpc.HelloServiceServicer): def SayHello(self, request, context): return hello_pb2.HelloResponse(message='Hello, %s!' % request.name) def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) hello_pb2_grpc.add_HelloServiceServicer_to_server(HelloServicer(), server) server.add_insecure_port('[::]:50051') server.start() try: while True: time.sleep(3600) except KeyboardInterrupt: server.stop(0) if __name__ == '__main__': serve() ``` 5. 编写 gRPC 客户端代码 ```python import grpc import hello_pb2 import hello_pb2_grpc def run(): with grpc.insecure_channel('localhost:50051') as channel: stub = hello_pb2_grpc.HelloServiceStub(channel) response = stub.SayHello(hello_pb2.HelloRequest(name='World')) print("Greeter client received: " + response.message) if __name__ == '__main__': run() ``` 以上就是在 Python 环境下配置 gRPC 的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值