使用python asyncio从套接字读取时如何避免阻塞?

时间:2018-06-19 13:19:42

标签: python python-3.x python-asyncio python-sockets

我正在尝试使用python asyncio进行一些改进,以达到该方面的目的,出于自学目的,我尝试连接到redis,发送一些命令并读取响应,这可能属于“读取流”来自某些来源的数据”。我无法解决的问题是如何读取块中的数据,因为服务器与客户端之间的连接并未关闭,并且终止序列\r\n可能会多次遇到。当然,如果我等没有更多数据时,通话将阻塞,直到收到其他信息为止。

class Client:
    def __init__(self, loop, host='127.0.0.1', port=6379):
        self.host = host
        self.port = port
        self.reader = None
        self.writer = None
        self.loop = loop

    @asyncio.coroutine
    def _connect(self):
        self.reader, self.writer = yield from asyncio.open_connection(
            self.host, self.port, loop=self.loop)

    async def read(self, b=4096):
        resp = b''
        while True:
            chunk = await self.reader.read(b)
            if chunk:
                resp += chunk
            else:
                break
        return resp

假装我想以2个字节的块读取响应(是愚蠢的,但这只是出于学习目的),所以:

loop = asyncio.get_event_loop()
client = Client(loop)
..... sends some commands here ....
resp = await client.read(2)

我不知道如何在不知道服务器响应长度的情况下,当响应长于从套接字读取的字节时,代码仍然可以保持安全。

1 个答案:

答案 0 :(得分:0)

我最近遇到了类似的问题。我的解决方案是继续读取,直到读取了给定的字符(或一组字符)为止。这是人们说话完成后在对讲机上说“结束”时所遵循的相同哲学。仅等待响应说完成对话就容易了。

虽然我以前没有使用过asyncio模块,但我相信以下代码应该可以解决您的问题,假设输入源以变量中指示的任何字符(或字符串)结束响应end_signal

class Client:
    def __init__(self, loop, host='127.0.0.1', port=6379):
        self.host = host
        self.port = port
        self.reader = None
        self.writer = None
        self.loop = loop

    @asyncio.coroutine
    def _connect(self):
        self.reader, self.writer = yield from asyncio.open_connection(
            self.host, self.port, loop=self.loop)

    async def read(self, b=4096, end_signal = "10101101110111110"):
        resp = b''
        while True:
            chunk = await self.reader.read(b)
            resp += chunk
            if resp[-1*len(end_signal):] == end_signal:
                break
        return resp