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

使用python asyncio从套接字读取时如何避免阻塞?,python,python-3.x,python-asyncio,python-sockets,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)

我正在尝试使用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个字节的块读取响应(是的,这很愚蠢,但只是为了学习目的),因此:


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

我最近遇到了类似的问题。我的解决方案是继续读取,直到读取给定的字符(或字符集)。这与人们在结束通话后用对讲机说“结束”的理念是一样的。更容易的方法是等待回应,说已经结束了

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

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

相关:ReadTill似乎可以完成这项工作,但仍然不适合需要完全控制区块大小的情况。将终止序列更改为仅在终止时使用的序列。我无法更改服务器响应我的方式。如何在响应中多次出现终止序列?终止序列的定义不是终止响应的东西吗?您能展示一下如何用普通的阻塞套接字实现您所需要的吗?代码?这还不是一个真正的答案,尽管它有可能是一个。问题是,因此我的问题是,如果终止序列未知,或者像redis中那样,它可以在响应中多次出现,那么如何避免阻塞?这不是一个重新实现的代码吗?不,这是正确的方法。ReadTill将一直读取,直到找到序列为止,这意味着如果响应是
$6\r\nabcdef\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, 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