2016-05-22 25 views
11

Chciałbym połączyć się z internetowym gniazdem poprzez asyncio i websockets, w formacie pokazanym poniżej. Jak mógłbym to osiągnąć?Jak mogę wdrożyć asyncio websockets w klasie?

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!" 

Odpowiedz

12

Jak pisać programy asynchroniczne?

  1. Należy określić funcs async z async
  2. Należy zadzwonić asynchroniczny funcs z await
  3. Trzeba event loop aby uruchomić program asynchroniczny

Wszystko inne jest prawie taka sama jak w przypadku zwykłej Pythonie programy.

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

wyjściowa:

Hello! 

Jak widać, kod jest prawie taka sama jak napisałeś.

Jedyna różnica polega na tym, że websockets.connect został zaprojektowany jako menedżer kontekstów asynchronicznych (używa __aenter__, __aexit__). Konieczne jest zwolnienie połączenia, a także ułatwi wykonywanie operacji asynchronicznych podczas inicjowania klasy (ponieważ nie mamy asynchronicznej wersji __init__).

Radzę zorganizować swoją klasę w ten sam sposób. Ale jeśli naprawdę nie chcesz używać menedżera kontekstowe jakiegoś powodu można korzystać z nowej metody __await__ dokonać inicjalizacji transmisji asynchronicznej i kilka innych funkcji asynchronicznej, aby zwolnić połączenie:

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

Wiele przykładów wykorzystania websockets można znaleźć w to jest docs.

+1

Ta odpowiedź zasługuje na podziękowanie. – pylang

+0

to kończy się po otrzymaniu odpowiedzi. Jak mógł kontynuować otrzymywanie wiadomości? – FeedTheWeb

+0

@FeedTheWeb po prostu otrzymywać odpowiedzi wewnątrz menedżera kontekstu. –