protobuf
syntax = "proto3";
option go_package = "./;proto";
service StreamRpc{
rpc GetServerResult(Requests) returns (Reply);
rpc GetServerStream(Requests) returns (stream Reply);
rpc ClientSendStream(stream Requests) returns (Reply);
rpc ServerClientStream(stream Requests) returns (stream Reply);
}
message Requests {
string data = 1;
}
message Reply{
string result = 1;
}
server
import asyncio
import time
import grpc
from rpc.async_grpc_stream.proto import stream_data_pb2, stream_data_pb2_grpc
class AsyncStreamServer(stream_data_pb2_grpc.StreamRpcServicer):
# 一元调用
async def GetServerResult(self, request, context):
print("GetServerResult 服务器接收到的数据是: ", request.data)
return stream_data_pb2.Reply(result="hell tnan")
# 服务器发送流式数据给客户端
async def GetServerStream(self, request, context):
print("GetServerStream 服务器接收到的数据是: ", request.data)
for i in range(10):
# 通过context rpc上下文 来异步发送流数据
await context.write(stream_data_pb2.Reply(result="{}".format(i)))
# 服务器接收客户端流式数据
async def ClientSendStream(self, request_iterator, context):
async for i in request_iterator:
print(i)
await asyncio.sleep(1)
print("结束: ", time.time())
return stream_data_pb2.Reply(result="aabbbbbb")
# 服务端发送stream数据协程
async def ServerSendStreamClient(self, context):
for i in range(5):
print("服务器正在往客户端流式发送数据: ", i)
await context.write(stream_data_pb2.Reply(result="{}".format(i)))
await asyncio.sleep(1)
# 服务器接收客户端stream 数据协程
async def RecvClientStream(self, request_iterator):
async for i in request_iterator:
print("服务器接收到客户端流式数据: ", i)
print("数据接收结束")
# 双向流
async def ServerClientStream(self, request_iterator, context):
# 添加两个协程任务,等待协程任务执行完毕
await asyncio.gather(
self.ServerSendStreamClient(context),
self.RecvClientStream(request_iterator)
)
async def main():
# 创建grpc 异步服务器
g = grpc.aio.server()
g.add_insecure_port("0.0.0.0:8659")
stream_data_pb2_grpc.add_StreamRpcServicer_to_server(AsyncStreamServer(), g)
await g.start()
await g.wait_for_termination()
if __name__ == '__main__':
asyncio.run(main())
client
import asyncio
import time
import grpc
from rpc.async_grpc_stream.proto import stream_data_pb2, stream_data_pb2_grpc
class ClientStream:
def __init__(self):
self.channel = grpc.aio.insecure_channel("127.0.0.1:8659")
self.sub = stream_data_pb2_grpc.StreamRpcStub(channel=self.channel)
async def GetServerResult(self):
# 异步调用rpc
result = await self.sub.GetServerResult(stream_data_pb2.Requests(data="aaa"))
print("GetServerResult result: ", result)
# 单向流
async def GetServerStream(self):
# 获取单向流对象
stream_client = self.sub.GetServerStream(stream_data_pb2.Requests(data="aaa"))
# 通过异步for 循环获取响应数据
async for i in stream_client:
print("GetServerStream result : ", i)
# 单向流
async def ClientSendStream(self):
# 获取单向流对象
stream_client = self.sub.ClientSendStream()
for i in range(10):
await stream_client.write(stream_data_pb2.Requests(data="{}".format(i)))
# 客户端使用异步发送流数据需要手动关闭,客户端使用同步调用发送流数据的时候是不需要手动关闭的:
# 同步调用代码如下:
# def Client_send_stream(self):
# index = 0
# while 1:
# index += 1
# yield stream_data_pb2.Requests(data="{}".format(index))
# # time.sleep(1)
# if index == 10:
# break
# print("已结束")
# result = self.stub.ClientSendStream(Client_send_stream())
# 个人猜测是因为同步调用是通过另一个函数方法通过yield生成发送数据,当这个yield生成发送数据方法结束后在
# ClientSendStream中封装了 自动关闭的功能, 因为同步调用执行完 result 这行代码就可以关闭这次调用了
# 而异步调用是不会堵塞的, 就意味着,无法在 stream_client = self.sub.ClientSendStream() 期间进行封装
# 关闭功能,如果在 stream_client 这个流对象生命期间封装 关闭功能的话, 这个ClientSendStream方法在发送完流数据后
# 可能会做一下其他的事情, 如: 我在发送完流数据后做一些耗时的扫尾工作,导致这次的rpc调用迟迟无法结束,这会占用服务器
# 的资源,所以,在 stream_client 生命周期做关闭功能封装也是不现实的,所以就需要我们手动关闭
await stream_client.done_writing()
data = await stream_client
print("ClientSendStream result: ", data)
# 双向流客户端往服务器发送流数据
async def ClientSendStreamServer(self, stream_client):
for i in range(6):
print("正在往服务器发送流式数据: ", i, time.time())
await stream_client.write(stream_data_pb2.Requests(data="send data {}".format(i)))
await asyncio.sleep(2)
await stream_client.done_writing()
# 双向流 接收服务器发送的流数据
async def RecvServerStream(self, stream_client):
async for i in stream_client:
print("接收到服务器流式数据: ", i)
print("数据接收结束", time.time())
# 双向流
async def ServerClientStream(self):
stream_client = self.sub.ServerClientStream()
# 将 接收流、发送流 方法添加到事件循环中, 等待这两个方法结束
await asyncio.gather(
self.ClientSendStreamServer(stream_client),
self.RecvServerStream(stream_client)
)
async def main():
client_stream = ClientStream()
await client_stream.ClientSendStream()
if __name__ == '__main__':
client_stream = ClientStream()
asyncio.run(main())
查看grpc 异步方法
可以在grpc.aio 包中查看grpc提供的异步方法