【问题标题】:How can I implement asyncio websockets in a class?如何在一个类中实现 asyncio websockets?
【发布时间】:2016-09-19 02:03:58
【问题描述】:

我想通过asynciowebsockets连接到一个websocket,格式如下图。我怎样才能做到这一点?

from websockets import connect


class EchoWebsocket:

    def __init__(self):
        self.websocket = self._connect()

    def _connect(self):
        return connect("wss://echo.websocket.org")

    def send(self, message):
        self.websocket.send(message)

    def receive(self):
        return self.websocket.recv()

echo = EchoWebsocket()
echo.send("Hello!")
print(echo.receive())  # "Hello!"

【问题讨论】:

    标签: python python-3.x websocket python-3.5 python-asyncio


    【解决方案1】:

    如何编写异步程序?

    1. 你应该用async定义异步函数
    2. 您应该调用 async 功能与await
    3. 你需要event loop 来启动你的异步程序

    所有其他几乎与常规 Python 程序相同。

    import asyncio
    from websockets import connect
    
    
    class EchoWebsocket:
        async def __aenter__(self):
            self._conn = connect("wss://echo.websocket.org")
            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()
    
    
    async def main():
        async with EchoWebsocket() as echo:
            await echo.send("Hello!")
            print(await echo.receive())  # "Hello!"
    
    
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    

    输出:

    Hello!
    

    如您所见,代码与您编写的几乎相同。

    唯一的区别是websockets.connect 设计为异步上下文管理器(它使用__aenter____aexit__)。释放连接是必要的,并且还会帮助您在类初始化期间进行异步操作(因为我们没有 __init__ 的异步版本)。

    我建议您以同样的方式组织课程。但是如果你真的因为某种原因不想使用上下文管理器,你可以使用新的__await__ 方法进行异步初始化和其他一些异步函数来释放连接:

    import sys
    import asyncio
    from websockets import connect
    
    
    class EchoWebsocket:
        def __await__(self):
            # see: http://stackoverflow.com/a/33420721/1113207
            return self._async_init().__await__()
    
        async def _async_init(self):
            self._conn = connect("wss://echo.websocket.org")
            self.websocket = await self._conn.__aenter__()
            return self
    
        async def close(self):
            await self._conn.__aexit__(*sys.exc_info())
    
        async def send(self, message):
            await self.websocket.send(message)
    
        async def receive(self):
            return await self.websocket.recv()
    
    
    async def main():
        echo = await EchoWebsocket()
        try:
            await echo.send("Hello!")
            print(await echo.receive())  # "Hello!"
        finally:
            await echo.close()
    
    
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    

    您可以在docs 中找到许多使用websockets 的示例。

    【讨论】:

    • 收到回复后关闭。它怎么会继续接收消息?
    • @FeedTheWeb 只是在上下文管理器中不断接收回复。
    • @MikhailGerasimov 我不明白上面的评论。您如何确保脚本不会在一次回复后结束?谢谢
    • @HJA24 如果你想不断地发送/接收数据,你通常启动一个服务器。例如,查看a code snippet here,特别是server.serve_forever() 行。启动服务器的具体方法取决于您要实现的目标。用于启动与 asyncio 一起使用的服务器的流行高级库是 aiohttp。它提供了一种使用多种协议的方法including websockets
    • @MikhailGerasimov 嗨,我正在关注不同来源的文档,他们不使用 server.serve.forever(),所以我有点困惑。你能看看我关于 SO stackoverflow.com/questions/61216022/… 的问题吗
    猜你喜欢
    • 2020-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-16
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多