这几天想在公司推广 GRPC,所以自己动手写了一些范例,今天的范例主要是获取详情和获取列表
先来看看客户端请求的结果
python3 -m app.client.main received: {"id": 1, "username": "yufei1"} received: {"users": [{"id": 1, "username": "yufei1"}, {"id": 2, "username": "yufei2"}]}
- 第一行是获取详情的结果返回
- 第二行是获取列表的结果返回
环境
- 苹果电脑,其实任意电脑都可以
- Python 3.7.4
- virutalenv 环境
准备
-
创建一个范例项目
pgrpc
mkdir pgrpc
-
初始化
virtualenv
cd pgrpc python3 -mvenv . bin/activate
-
安装必要的第三方库
pip install grpcio protobuf grpcio-tools
如果安装太慢,建议使用 douban 源
https://mirrors.aliyun.com/pypi/simple/
-
创建
app
目录和必要的文件,目录结果如下app ├── __init__.py ├── client # 客户端代码目录 │ └── main.py ├── proto # 协议目录 │ ├── __init__.py │ ├── user.proto └── server # 服务器端代码目录 └── main.py
-
创建协议
app/proto/user.proto
文件,内容如下syntax = "proto3"; package proto; service UserService { rpc GetUserById(DetailRequest) returns (User){} rpc GetUsers(QueryUserListRequest) returns (UserList){} } message QueryUserListRequest { uint64 started_at = 1; uint64 ended_at = 2; } message DetailRequest { int32 id = 1; } message UserList { repeated User users = 1; } message User { int32 id = 1; string username = 2; }
-
编译协议。 在
pgrpc
目录下运行下面的命令python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./app/proto/user.proto
注意: 不要相信其它文章的在
proto
目录下运行,可能会抱错的from app.proto import user_pb2, user_pb2_grpc ImportError: cannot import name 'user_pb2' from 'app.proto' (unknown location)
-
编写服务器端代码
import logging import concurrent import grpc from app.proto import user_pb2, user_pb2_grpc _HOST = 'localhost' _PORT = '8080' class UserService(user_pb2_grpc.UserServiceServicer): def GetUserById(self,request,context): user_id = request.id return user_pb2.User(id=request.id, username="yufei" + str(request.id)) def GetUsers(self,request,context): users = user_pb2.UserList() users.users.append(user_pb2.User(id=1,username="yufei1")) users.users.append(user_pb2.User(id=2,username="yufei2")) return users; def serve(): # 指定最多可以有 4 个线程来处理请求 grpcServer = grpc.server(concurrent.futures.ThreadPoolExecutor(max_workers=4)) # 将相应的服务注册到 grpc 中 user_pb2_grpc.add_UserServiceServicer_to_server(UserService(), grpcServer) # 指定端口并且非 ssl 模式 grpcServer.add_insecure_port(_HOST + ':' + _PORT) grpcServer.start() # 等待结束,不然进程会立刻退出 grpcServer.wait_for_termination() if __name__ == '__main__': logging.basicConfig() serve()
-
运行服务器代码。在
pgrpc
目录下运行下面的命令python3 -m app.server.main
-
编写客户端代码
import json import grpc from google.protobuf.json_format import MessageToDict from app.proto import user_pb2, user_pb2_grpc _HOST = 'localhost' _PORT = '8080' def run(): # 连接到 grpc 服务器 conn = grpc.insecure_channel(_HOST + ':' + _PORT) # 连接到相关的服务 client = user_pb2_grpc.UserServiceStub(channel=conn) # 请求内容 user = client.GetUserById(user_pb2.DetailRequest(id=1)) # 输出结果 print('received:',json.dumps(MessageToDict(user))) # 请求内容 users = client.GetUsers(user_pb2.QueryUserListRequest(started_at=0,ended_at=0)) # 输出结果 print('received:',json.dumps(MessageToDict(users))) if __name__ == '__main__': run()
-
运行客户端代码,输出结果
python3 -m app.client.main
运行结果如下
received: {"id": 1, "username": "yufei1"} received: {"users": [{"id": 1, "username": "yufei1"}, {"id": 2, "username": "yufei2"}]}
目前尚无回复