websockets cannot communicate after the program recieved interrupt signal

35 Views Asked by At

My server:

import websockets
async def handler(ws):
  async for message in ws:
    print(message)
    await ws.send('received' + message)
server = await websockets.serve(handler, 'localhost', 22235)

My client:

import websockets
import asyncio
import json

async def keep_recv():
  ws = await websockets.connect('ws://localhost:22235')
  while True:
    try:
      response = await ws.recv()
      print(f"Received from server: {response}")
      await asyncio.create_task(asyncio.sleep(10000))
    finally:
      print('cancelled')
      await ws.send('client cancelled')
      response = await ws.recv()
      print(f"Received from server: {response}")
      break

asyncio.run(keep_recv())

When I pressed ctrl+c in my client, I expect client to output:

cancelled
Received from server: client cancelled

And server to output:

client cancelled

But in reality, the outputs are

client:

cancelled

server has no output.

After a while (probably waiting at ws.send), the client will yield KeyboardInterrupt error and exit, and the server will output websockets.exceptions.ConnectionClosedError: no close frame received or sent error and continue to run.

Does websockets stop communication after the program received the interrupt signal? How should i get it to work?

Additionally, trying to catch any error in the client simply does not work. I expect in client

    try:
      response = await ws.recv()
      print(f"Received from server: {response}")
      await asyncio.create_task(asyncio.sleep(10000))
    expect Exception as e:
      print(e)
    finally:

to print the error (asyncio.CancelledError), but no, it just skip right to the finally part. No sure why this is happening either.

1

There are 1 best solutions below

0
Alexandr Ch On

I would suggest to use an explicit asyncio exception call (e.g., asyncio.CancelledError) before catching the general Except, since in async code exceptions can be raised asynchronously and may require separate handling to catch them.

So, your code may be modified as follows:

import websockets
import asyncio
import json

async def keep_recv():
  async with websockets.connect('ws://localhost:22235') as ws:
    try:
        while True:
            try:
                response = await ws.recv()
                print(f"Received from server: {response}")
                await asyncio.create_task(asyncio.sleep(10000))
            except websockets.exceptions.ConnectionClosedOK:
                await ws.send('client cancelled')
                print('Connection closed by server')
                break
            except asyncio.CancelledError:
                print('Coroutine cancelled')
                await ws.send('client cancelled')
                break
            except Exception as e:
                print(f"Error: {e}")
                break
    finally:
        await ws.close()

asyncio.run(keep_recv())