为啥当客户端断开连接时这个简单的 websocket 代码会抛出?

Posted

技术标签:

【中文标题】为啥当客户端断开连接时这个简单的 websocket 代码会抛出?【英文标题】:Why does this simple websocket code throw when the client disconnects?为什么当客户端断开连接时这个简单的 websocket 代码会抛出? 【发布时间】:2018-10-07 09:59:40 【问题描述】:

我正在编写一些基于these docs 的简单网络套接字代码。服务器应侦听网络套接字并仅使用 pong 响应 ping 消息。

我在 Python3 上运行,服务器代码如下所示:

import asyncio
import websockets
from jsonrpcserver.aio import methods
from jsonrpcserver.response import NotificationResponse

@methods.add
async def ping():
    return 'pong'

async def accept_connection(websocket, path):
    async for request in websocket:
        response = await methods.dispatch(request)
        if not response.is_notification:
            await websocket.send(str(response))

start_server = websockets.serve(accept_connection, 'localhost', 5000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

客户端在 Dart 中,只需调用两次 ping 然后关闭连接。当客户端断开连接时,服务器的输出会出现此错误:

Dannys-MacBook:pythonws danny$ python3 server.py 
--> "jsonrpc":"2.0","method":"ping","id":0
<-- "jsonrpc": "2.0", "result": "pong", "id": 0
--> "jsonrpc":"2.0","method":"ping","id":1
<-- "jsonrpc": "2.0", "result": "pong", "id": 1
Error in connection handler
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/websockets/server.py", line 152, in handler
    yield from self.ws_handler(self, path)
  File "server.py", line 11, in accept_connection
    async for request in websocket:
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/websockets/py36/protocol.py", line 15, in __aiter__
    yield await self.recv()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/websockets/protocol.py", line 350, in recv
    yield from self.ensure_open()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/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 = 1005 (no status code [internal]), no reason

根据上面链接的文档:

当客户端断开连接时迭代终止。

这让我相信它应该退出 async for 循环而不是抛出?

【问题讨论】:

【参考方案1】:

https://www.pydoc.io/pypi/websockets-6.0/autoapi/protocol/index.html

迭代器产生传入消息。当连接关闭且状态码为 1000(OK)或 1001(正在消失)时,它会正常退出。当连接以任何其他状态码关闭时,它会引发 ConnectionClosed 异常。

从客户端以 1000 状态关闭可防止异常。

【讨论】:

以上是关于为啥当客户端断开连接时这个简单的 websocket 代码会抛出?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我移动到新场景时蓝牙会断开连接?

websock使用

为啥当客户端关闭连接时我的简单 C 服务器退出?

socket.io 通过 XHR 轮询强制断开连接

XMPP 流发送,不接收。为啥 XMPP 流可能会断开连接?

Hazelcast 客户端与整个集群断开连接