程序接收到中断信号后WebSocket无法通信

0 投票
1 回答
31 浏览
提问于 2025-04-12 22:14

我的服务器:

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)

我的客户端:

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

当我在客户端按下 ctrl+c 时,我希望客户端输出:

cancelled
Received from server: client cancelled

而服务器输出:

client cancelled

但实际上,输出是:

客户端:

cancelled

服务器没有任何输出。

过了一段时间(可能是在等待 ws.send),客户端会出现 KeyboardInterrupt 错误并退出,而服务器会输出 websockets.exceptions.ConnectionClosedError: no close frame received or sent 错误,并继续运行。

在程序收到中断信号后,websockets 会停止通信吗?

我该如何让它正常工作?

另外,尝试在客户端捕获任何错误根本没有用。我希望在客户端:

    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:

打印出错误(asyncio.CancelledError),但没有,它只是直接跳到 finally 部分。我也不太明白为什么会这样。

1 个回答

0

我建议在捕捉一般的异常之前,先使用一个明确的 asyncio 异常调用(比如 asyncio.CancelledError)。因为在异步代码中,异常可能会异步发生,这些异常可能需要单独处理才能捕捉到。

所以,你的代码可以修改成这样:

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

撰写回答