我正在尝试使用websockets
和我以前从未使用过的强制性asyncio
在python中实现一个websocket客户端(并且我很难理解...)。
我已经阅读了很多有关该主题的文章,并且在各处和任何地方都看到(太多)示例,但是我找不到一种方法来正确地建立具有持久连接的websocket客户端。
根据我在这里到处发现的示例(带有一些混淆的数据),这就是我现在拥有的:
import json
import asyncio
from websockets import connect
URL = 'wss://server.com/endpoint'
class Websocket:
async def __aenter__(self):
self._conn = connect(URL)
self.websocket = await self._conn.__aenter__()
return self
async def __aexit__(self, *args, **kwargs):
await self._conn.__aexit__(*args, **kwargs)
async def send(self, message):
await self.websocket.send(message)
async def receive(self):
return await self.websocket.recv()
class Handler:
def __init__(self):
self.wws = Websocket()
self.loop = asyncio.get_event_loop()
def command(self, cmd):
return self.loop.run_until_complete(self.__async__command(cmd))
async def __async__command(self, cmd):
async with self.wws as echo:
await echo.send(json.dumps(cmd))
return await echo.receive()
def main():
handler = Handler()
foo = handler.command('authentication command')
print('auth: ', foo)
bar = handler.command('another command to run depending on the first authentication')
print('command: ', bar)
if __name__ == '__main__':
main()
基本上现在我得到了这些答案(简化和混淆):
auth: Ok, authenticated
command: Command refused, not authenticated
我想我的问题是,块async with self.wws as echo:
会创建连接,先运行其代码然后将其删除,而不是保持连接处于活动状态。由于我们在这里使用的不是常用的__init__
,而是一些我不理解的asyncio
伏都教徒,所以我有些困惑。
答案 0 :(得分:1)
我认为您的诊断是正确的,问题在于它为每个Handler.command
的调用创建并关闭连接的异步上下文管理器...确实不想要您想要的。
相反,您可以在Handler
初始化期间同步建立websocket连接,然后将连接websocket(类型为WebSocketClientProtocol
的实例)存储为类成员,以供以后使用,如此示例代码中所示:
import json
import asyncio
from websockets import connect
URL = 'ws://localhost:8000'
class Handler:
def __init__(self):
self.ws = None
self.loop = asyncio.get_event_loop()
# perform a synchronous connect
self.loop.run_until_complete(self.__async__connect())
async def __async__connect(self):
print("attempting connection to {}".format(URL))
# perform async connect, and store the connected WebSocketClientProtocol
# object, for later reuse for send & recv
self.ws = await connect(URL)
print("connected")
def command(self, cmd):
return self.loop.run_until_complete(self.__async__command(cmd))
async def __async__command(self, cmd):
await self.ws.send(json.dumps(cmd))
return await self.ws.recv()
def main():
handler = Handler()
foo = handler.command('authentication command')
print('auth: ', foo)
bar = handler.command('another command to run depending on the first authentication')
print('command: ', bar)
if __name__ == '__main__':
main()