web-dev-qa-db-fra.com

Comment puis-je implémenter des websockets asyncio dans une classe?

Je voudrais me connecter à une websocket via asyncio et websockets, avec un format comme indiqué ci-dessous. Comment pourrais-je y parvenir?

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!"
20
2Cubed

Comment écrire des programmes asynchrones?

  1. Vous devez définir des fonctions asynchrones avec async
  2. Vous devez appeler des fonctions asynchrones avec await
  3. Vous avez besoin de boucle d'événement pour démarrer votre programme asynchrone

Tous les autres sont presque les mêmes qu'avec les programmes Python réguliers.

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())

Production:

Hello!

Comme vous le voyez, le code est presque le même que celui que vous avez écrit.

La seule différence est que websockets.connect conçu pour être un gestionnaire de contexte asynchrone (il utilise __aenter__, __aexit__). Il est nécessaire de libérer la connexion et vous aidera également à effectuer des opérations asynchrones pendant l'initialisation de la classe (car nous n'avons pas de version asynchrone de __init__).

Je vous conseille d'organiser votre cours de la même manière. Mais si vous ne voulez vraiment pas utiliser le gestionnaire de contexte pour une raison quelconque, vous pouvez utiliser le nouveau __await__ méthode pour effectuer l'initialisation asynchrone et une autre fonction asynchrone pour libérer la connexion:

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())

Vous trouverez de nombreux exemples d'utilisation de websockets dans son docs .

24