亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

asyncio.start_unix_server 和 redis 的套接字錯誤

asyncio.start_unix_server 和 redis 的套接字錯誤

瀟瀟雨雨 2023-11-09 21:29:42
我正在嘗試使用 asyncio 和 Unix 域套接字在 Python 中構建一個玩具內存 Redis 服務器。baz我的最小示例只返回每個請求的值:import asyncioclass RedisServer:    def __init__(self):        self.server_address = "/tmp/redis.sock"    async def handle_req(self, reader, writer):        await reader.readline()        writer.write(b"$3\r\nbaz\r\n")        await writer.drain()        writer.close()        await writer.wait_closed()    async def main(self):        server = await asyncio.start_unix_server(self.handle_req, self.server_address)        async with server:            await server.serve_forever()    def run(self):        asyncio.run(self.main())RedisServer().run()當我使用以下腳本使用客戶端庫測試兩個連續的客戶端請求時,它可以redis工作:import timeimport redisr = redis.Redis(unix_socket_path="/tmp/redis.sock")r.get("foo")time.sleep(1)r.get("bar")但是,如果我刪除time.sleep(1),有時它會起作用,有時第二個請求會失敗,并出現以下任一情況:Traceback (most recent call last):  File "/tmp/env/lib/python3.8/site-packages/redis/connection.py", line 706, in send_packed_command    sendall(self._sock, item)  File "/tmp/env/lib/python3.8/site-packages/redis/_compat.py", line 9, in sendall    return sock.sendall(*args, **kwargs)BrokenPipeError: [Errno 32] Broken pipeDuring handling of the above exception, another exception occurred:Traceback (most recent call last):  File "test.py", line 9, in <module>    r.get("bar")  File "/tmp/env/lib/python3.8/site-packages/redis/client.py", line 1606, in get    return self.execute_command('GET', name)  File "/tmp/env/lib/python3.8/site-packages/redis/client.py", line 900, in execute_command    conn.send_command(*args)  File "/tmp/env/lib/python3.8/site-packages/redis/connection.py", line 725, in send_command    self.send_packed_command(self.pack_command(*args),  File "/tmp/env/lib/python3.8/site-packages/redis/connection.py", line 717, in send_packed_command    raise ConnectionError("Error %s while writing to socket. %s." %redis.exceptions.ConnectionError: Error 32 while writing to socket. Broken pipe.看來我的實現缺少客戶端庫期望的一些關鍵行為(可能是由于它是異步的)。我缺少什么?
查看完整描述

1 回答

?
拉風的咖菲貓

TA貢獻1995條經驗 獲得超2個贊

write_eof()如果您想在每次請求后關閉套接字,則需要使用

緩沖的寫入數據刷新后,關閉流的寫入端。

您的代碼稍加修改將如下所示:

async def handle_req(self, reader, writer):

? ? await reader.readline()

? ? writer.write(b"$3\r\nbaz\r\n")

? ? await writer.drain()

? ? writer.write_eof()

? ? writer.close()

? ? await writer.wait_closed()

通常,您不會在每次請求后關閉套接字。


以下示例僅用于說明目的,旨在表明套接字不需要關閉。當然,您總是會讀取一行,然后根據 Redis 協議解釋數據。我們知道這里發送了兩個 GET 命令(每行 5 行,包含 2 個元素的數組的指示符,字符串的指示符,字符串值“GET”,以及字符串指示符和相應的值,即鍵)


async def handle_req(self, reader, writer):

? ? print("start")

? ? for i in range(0, 2):

? ? ? ? for x in range(0, 5):

? ? ? ? ? ? print(await reader.readline())

? ? ? ? writer.write(b"$3\r\nbaz\r\n")

? ? ? ? await writer.drain()

? ? writer.write_eof()

? ? writer.close()

? ? await writer.wait_closed()

在客戶端發送是這樣完成的:


print(r.get("foo"))

print(r.get("bar"))

time.sleep(1)

最后一次time.sleep是為了確??蛻舳瞬粫⒓赐顺?。


控制臺上的輸出是:


start

b'*2\r\n'

b'$3\r\n'

b'GET\r\n'

b'$3\r\n'

b'foo\r\n'

b'*2\r\n'

b'$3\r\n'

b'GET\r\n'

b'$3\r\n'

b'bar\r\n'

請注意,start僅輸出一次,這表明我們可以處理多個請求,而不必立即關閉套接字。


查看完整回答
反對 回復 2023-11-09
  • 1 回答
  • 0 關注
  • 133 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號