Python websockets lib客户端持久连接(带类实现)

标签 python websocket python-asyncio

我正在尝试使用 websockets 和我以前从未使用过的明显强制的 asyncio 在 python 中实现 websocket 客户端(而且我很难理解。 ..).

我读过很多关于这个主题的文章,并且到处都看到了(太多)很多例子,但我找不到一种方法来正确地创建具有持久连接的 websocket 客户端。

  • 我需要有一个持久连接,因为需要在同一连接上请求这些命令,第一个是身份验证命令。
  • 远程服务器是第三方 API,我无法控制。
  • 我想我可以与程序发送的每个命令一起运行身份验证请求,但对每个命令打开 > 身份验证 > 请求 > 关闭而不是在整个程序生命周期中保持一个连接处于事件状态是不合适的
  • 我的实现是一个使用许多类的库,我需要将 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

我想我的问题是 block async with self.wws as echo: 类型创建连接,运行其代码然后删除它而不是保持连接处于事件状态。由于我们在这里没有使用通常的 __init__ ,而是使用了一些我不明白的 asyncio 巫术,所以我有点卡住了。

最佳答案

我认为您的诊断是正确的,问题是异步上下文管理器为每次调用 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()

关于Python websockets lib客户端持久连接(带类实现),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59182741/

相关文章:

java - Web 套接字客户端在 Tomcat 中不工作

python-3.x - 计算事件循环中的事件任务

python - PIL 和使用 asyncio 的阻塞调用

c++ - 在 Winsock ws 客户端和 Websocket 服务器之间建立握手

python - asyncio.new_event_loop 创建的事件循环挂起

python - 当我想要的时候 GameOver 屏幕没有出现 - pygame

python - 示例使用查询集而不是 DetailView 扩展类的模型属性

python - 如何使用 Apache Beam Python 将输出写入动态路径

python - 为什么 Python 输出相同值的字符串和 unicode 不同?

html - WebSocket 不会连接到 127.0.0.1/localhost 以外的任何东西