python调用grpc请求
gRPC是一款高性能、开源的RPC框架,支持多种编程语言。Protobuf是gRPC使用的默认序化协议,可以将结构化数据序列化为二进制格式,提高数据传输效率。
在Python中使用gRPC调用服务时,通常需要先定义协议缓冲区(Protocol Buffers)消息类型,这些类型是从.proto文件生成的。当你准备调用一个gRPC服务时,需要根据该服务的请求消息类型来构造请求对象。
以下是一个步骤化的指南,展示如何封装proto对象并发送请求给gRPC服务:
步骤 1: 定义 .proto 文件
首先,你需要定义一个或多个 .proto 文件来描述你的服务以及它接受的消息格式。例如,假设你有一个简单的服务,它接受一个名字并返回一个带有问候的消息:
syntax = "proto3"; package greeting; // 请求消息 message HelloRequest { string name = 1; } // 响应消息 message HelloReply { string message = 1; } // 服务定义 service Greeter { rpc SayHello (HelloRequest) returns (HelloReply); }
步骤 2: 生成 Python 源代码
安装第三方包:grpcio、protobuf、grpcio_tools
pip install grpcio
pip install protobuf3
pip install grpcio_tools
使用 protoc 编译器和相关的插件来生成Python源代码。如果你已经设置了环境,可以运行如下命令:
python -m grpc_tools.protoc -I ./ --python_out=. --grpc_python_out=. helloworld.proto
这会在当前目录下生成两个文件:greeting_pb2.py 和 greeting_pb2_grpc.py。
参数说明:
python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. xxx.proto -I=/workspace -I=xxx/yyy/
- -I=:在proto文件中远程调用的内容,导入路径为实际调用的上一级目录即可。
- python_out:指定xxx_pb2.py的输出路径,编译生成处理protobuf相关的代码路径。传入.,则默认生成到当前目录。
- grpc_python_out:指定xxx_pb2_grpc.py的输出路径,编译生成处理grpc相关的代码路径,传入.,则默认生成到当前目录。
- grpc_tools.protoc:工具包,刚安装的。
- -I:这个参数指定协议文件的查找目录。
# 生成的文件中:
- xxx_pb2.py:里面有消息序列化类。是用来和protobuf数据进行交互。
- xxx_pb2_grpc.py:包含了服务器Stub类和客户端Stub类,以及待实现的服务RPC接口。是用来和grpc进行交互。
步骤 3: 构造请求并发送
接下来,编写一个Python脚本来构造请求并发送给gRPC服务:
import grpc import greeting_pb2 import greeting_pb2_grpc def greet(): # 创建一个 gRPC 的通道 with grpc.insecure_channel('localhost:50051') as channel: # 创建一个 gRPC 的 stub stub = greeting_pb2_grpc.GreeterStub(channel) # 封装请求消息 request = greeting_pb2.HelloRequest(name='World') # 发送请求并接收响应 response = stub.SayHello(request) # 处理响应 return response.message if __name__ == '__main__': print(greet())
这段代码做了以下几件事:
- 创建了一个 grpc.insecure_channel 到运行在 localhost 的 50051 端口的服务。
- 使用生成的 GreeterStub 类来创建一个 stub,它是用来与服务通信的。
- 创建了一个 HelloRequest 对象并设置其 name 字段。
- 通过调用 stub.SayHello 方法发送请求,并获取响应。
- 打印出响应中的 message 字段。
注意事项
- 确保服务正在运行并且监听在你指定的地址和端口上。
- 如果服务端点不在本地主机上,则可能需要使用安全连接,此时应该使用 grpc.secure_channel 并提供证书。
- 确保 .proto 文件版本匹配,并且正确导入了所有依赖项。
- 根据实际的应用场景调整端口号和其他网络配置。
以上就是使用Python调用gRPC服务的基本流程。如果你的服务涉及到更复杂的消息结构或逻辑,那么你可能需要调整请求的构造方式以适应这些需求。
进阶
当你的 .proto
文件定义的消息类型包含嵌套结构时,你需要在构造请求对象时也遵循这种层次结构。下面是一个具体的例子,展示如何处理嵌套的消息结构。
假设你有一个 .proto
文件,其中定义了一个请求消息类型,包含了嵌套的字段:
syntax = "proto3"; package example; message NestedRequest { string main_field = 1; Nested inner_message = 2; } message Nested { string nested_field = 1; repeated int32 numbers = 2; }
这个 NestedRequest
消息类型包含了一个字符串字段 main_field
和一个嵌套的 Nested
消息。Nested
消息又包含了一个字符串字段 nested_field
和一个整数列表 numbers
。
步骤 1: 生成 Python 源代码
使用 protoc 编译器生成 Python 源代码:
python -m grpc_tools.protoc -I ./ --python_out=. --grpc_python_out=. example.proto
这将在当前目录下生成 example_pb2.py
和 example_pb2_grpc.py
文件。
步骤 2: 构造请求并发送
编写一个 Python 脚本,用于构造请求并发送给 gRPC 服务:
import grpc import example_pb2 import example_pb2_grpc def send_nested_request(): # 创建一个 gRPC 的通道 with grpc.insecure_channel('localhost:50051') as channel: # 创建一个 gRPC 的 stub stub = example_pb2_grpc.YourServiceStub(channel) # 创建嵌套部分的消息 nested_message = example_pb2.Nested( nested_field="Nested Field Value", numbers=[1, 2, 3] ) # 创建顶层请求消息,并填充嵌套部分 request = example_pb2.NestedRequest( main_field="Main Field Value", inner_message=nested_message ) # 发送请求并接收响应 response = stub.YourMethod(request) # 处理响应 return response if __name__ == '__main__': response = send_nested_request() print(response)
在这段代码中:
创建了一个 example_pb2.Nested 对象,并设置了它的字段。
创建了一个 example_pb2.NestedRequest 对象,并在其 inner_message 字段中填入之前创建的嵌套消息。
通过 stub.YourMethod 方法发送请求,并获取响应。
注意事项
确保替换 YourServiceStub 和 YourMethod 为你实际的服务名和方法名。
检查服务是否在指定的地址和端口上运行。
如果你的 .proto 文件中有更多的嵌套层次,只需按照相同的模式继续构建即可。
这样,你就能够成功构造包含嵌套结构的消息,并通过 gRPC 发送给服务端。
高级
对于多层嵌套的情况,构造请求消息的过程是相似的,只是需要更多层次的对象创建和属性赋值。我们可以进一步扩展之前的例子来展示多层嵌套的消息类型如何构造。
假设你的 .proto
文件中定义了一个非常复杂的请求消息类型,其中包括多层嵌套:
syntax = "proto3"; package example; message MultiLayerRequest { string top_level_field = 1; Nested outer_message = 2; } message Nested { string nested_field = 1; repeated int32 numbers = 2; AnotherLevel another_level = 3; } message AnotherLevel { string deep_nested_field = 1; repeated float floats = 2; }
在这个例子中,MultiLayerRequest
包含了一个顶层字符串字段 top_level_field
和一个 Nested
类型的消息。Nested
消息又包含了一个字符串字段 nested_field
、一个整数列表 numbers
和另一个嵌套的消息 AnotherLevel
,而 AnotherLevel
又包含了一个字符串字段 deep_nested_field
和一个浮点数列表 floats
。
构造请求并发送
下面是构造多层嵌套请求消息并发送给 gRPC 服务的 Python 示例:
import grpc import example_pb2 import example_pb2_grpc def send_multi_layer_request(): # 创建一个 gRPC 的通道 with grpc.insecure_channel('localhost:50051') as channel: # 创建一个 gRPC 的 stub stub = example_pb2_grpc.YourServiceStub(channel) # 创建最深层的嵌套部分的消息 deep_nested_message = example_pb2.AnotherLevel( deep_nested_field="Deep Nested Field Value", floats=[1.1, 2.2, 3.3] ) # 创建中间层的嵌套部分的消息,并填充最深层的部分 nested_message = example_pb2.Nested( nested_field="Nested Field Value", numbers=[1, 2, 3], another_level=deep_nested_message ) # 创建顶层请求消息,并填充中间层的部分 request = example_pb2.MultiLayerRequest( top_level_field="Top Level Field Value", outer_message=nested_message ) # 发送请求并接收响应 response = stub.YourMethod(request) # 处理响应 return response if __name__ == '__main__': response = send_multi_layer_request() print(response)
在这个示例中:
- 首先创建了
AnotherLevel
消息,并设置了其字段。 - 接着创建了
Nested
消息,并在其another_level
字段中填入之前创建的AnotherLevel
消息。 - 最后创建了
MultiLayerRequest
消息,并在其outer_message
字段中填入之前创建的Nested
消息。
通过这种方式,你可以构造任意深度的嵌套消息。只要按照层次结构逐级创建消息对象并设置相应的字段,就能正确地构建请求消息。确保在实际使用时,替换 YourServiceStub
和 YourMethod
为你的服务和方法的实际名称。