How to keep connection alive with async websockets client?

Viewed 5926

I modified an example for a websocket client I found here like this:

import asyncio
import websockets
async def hello(messages):
    async with websockets.connect('ws://localhost:8765') as websocket:
        for m in ('msg1', 'msg2'):
            await websocket.send(m)
            print(f"> {m}")
            greeting = await websocket.recv()
            print(f"< {greeting}")
asyncio.get_event_loop().run_until_complete(hello(['name1', 'name2']))

But now I'm getting an exception as soon as the second send() gets executed:

Traceback (most recent call last):
  File "ws-client.py", line 44, in <module>
    main()
  File "ws-client.py", line 41, in main
    asyncio.get_event_loop().run_until_complete(hello(['name1', 'name2']))
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 468, in run_until_complete
    return future.result()
  File "ws-client.py", line 35, in hello
    greeting = await websocket.recv()
  File "/home/frans/.local/lib/python3.6/site-packages/websockets/protocol.py", line 350, in recv
    yield from self.ensure_open()
  File "/home/frans/.local/lib/python3.6/site-packages/websockets/protocol.py", line 512, in ensure_open
    self.close_code, self.close_reason) from self.transfer_data_exc
websockets.exceptions.ConnectionClosed: WebSocket connection is closed: code = 1000 (OK), no reason

I'm not so much into asyncio - can someone please tell me what I'm doing wrong?

I took the server code from the example as well..

2 Answers

You changed the client, but didn't change the server, so the problem is on the server side. Just check its code.

import asyncio
import websockets

async def hello(websocket, path):
    name = await websocket.recv()
    print(f"< {name}")

    greeting = f"Hello {name}!"

    await websocket.send(greeting)
    print(f"> {greeting}")

start_server = websockets.serve(hello, 'localhost', 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

After accepting a new connection it waits for the first message from the client, then sends it back and exits the handler. In effect, it just closes the connection. So, when your client tries to send the second message, it fails with the Connection closed error.

You can change the server like this, to repeat the handler payload twice.

  async def hello(websocket, path):
      for _ in range(2):  # or while True if you need an infinite echo server
          name = await websocket.recv()
          print(f"< {name}")

          greeting = f"Hello {name}!"

          await websocket.send(greeting)
          print(f"> {greeting}")

just check this link here I faced a similar problem that the connection was not kept open for a long time for me to actually do the things I wanted, so I checked this example and no more exceptions were thrown, the main thing you should change in your code should be

  • instead of
async def hello(websocket, path):

use

@async.coroutine
def hello (websocket,path)

thus the function will be eligible for becoming a coroutine generator

  • then replace await with yield from like
for m in ('msg1', 'msg2'):
            yield from websocket.send(m)
            print(f"> {m}")
            greeting = yield from websocket.recv()
            print(f"< {greeting}")

for more details see the github repo I mentioned above oh and as the above comment mentioned don't forget the infinite loop for continued messaging

Related