Google gRPC(Google Remote Procedure Call)是一个高性能、开源的远程过程调用框架,它允许客户端直接调用远程服务器上的方法,就像调用本地方法一样,屏蔽了网络通信的复杂性。
1. 配置安装
在正式编写代码之前,我们需要先完成开发环境的搭建与依赖包的安装。执行下面代码创建一个单独的虚拟环境,并安装 Python GRPC 需要的包。
# 创建虚拟环境 conda create -n grpc-env python=3.10 # 安装 gRPC 相关包 pip install grpcio grpcio-tools
- grpcio 用于运行 gRPC 客户端和服务端
- grpcio-tools 用于编译 .proto 文件
安装之后,我们创建一个 demo.proto 的 gRPC 服务定义文件,内容如下:
syntax = "proto3";
service Greeter
{
rpc sayHello (Request) returns (Response) {}
}
message Request
{
string name = 1;
int32 age = 2;
}
message Response
{
string message = 1;
}
- service Greeter:定义了一个服务,包含一个
sayHello方法
- Request/Response:定义了请求和响应的数据结构
接下来,在命令行中输入以下命令编译 proto 文件:
python -m grpc_tools.protoc -I. --python_out=pyi_out:. --grpc_python_out=. demo.proto
此时,会根据 proto 文件生成两个 py 文件:
- demo_pb2.py 对 message 进行操作的封装
- demo_pb2.pyi 用于提供静态类型信息提示
- demo_pb2_grpc.py 对 service 进行操作的封装
2. 远程调用
我们将接下来分别编写服务端与客户端的代码,实现一个完整的 gRPC 通信流程。
2.1 服务端
import grpc
from demo_pb2_grpc import GreeterServicer
from demo_pb2_grpc import add_GreeterServicer_to_server
from demo_pb2 import Request, Response
from concurrent import futures
# 实现服务接口
class MyGreeterServicer(GreeterServicer):
# request 表示客户端的请求参数对象
# context 表示一次客户端请求的上下文信息
def sayHello(self, request : Request, context : grpc.ServicerContext):
print('客户端:', context.peer())
for key, value in context.invocation_metadata():
print('元信息:', key, value)
print('请求参数:', request.name, request.age)
print('-' * 50)
# 当执行这一行代码时,终止后续调用并返回错误
context.abort(code=grpc.StatusCode.NOT_FOUND, details='出错了')
return Response(info='ok')
def run_server():
# 创建服务对象
# thread_pool: 用于执行 RPC 调用的线程池。服务端接收到请求后,会从线程池中分配线程来处理 handler 中的逻辑。
server = grpc.server(thread_pool=futures.ThreadPoolExecutor(max_workers=10))
# 设置服务端口
server.add_insecure_port('0.0.0.0:50052')
# 注册服务接口
add_GreeterServicer_to_server(MyGreeterServicer(), server)
# 开启服务
server.start()
server.wait_for_termination()
if __name__ == '__main__':
run_server()
2.2 客户端
import grpc
from demo_pb2 import Request, Response
from demo_pb2_grpc import GreeterStub
def demo():
channel = grpc.insecure_channel('127.0.0.1:50052')
stub = GreeterStub(channel)
# 构造请求元信息
metadata = (('token', 'abc123'), ('trace_id', 'trace-xyz-789'))
# 构造请求参数信息
request = Request(name='obama', age=20)
response : Response = stub.sayHello(request, metadata=metadata)
print('远程调用结果:', response.info)
if __name__ == '__main__':
demo()

冀公网安备13050302001966号