
本文旨在帮助开发者解决在使用 Jupyter Notebook API 通过 WebSocket 连接时遇到的 “socket is already closed” 错误。该错误通常发生在尝试接收服务器响应之前,WebSocket 连接意外关闭。本文将提供详细的排查思路和解决方案,包括检查连接参数、处理时区问题以及实现自动重连机制,确保代码能够稳定可靠地与 Jupyter Notebook Kernel 进行交互。
在使用 Jupyter Notebook API 时,通过 WebSocket 连接到 Kernel 是执行代码和获取结果的关键步骤。 然而,有时会遇到 “socket is already closed” 错误,导致无法正常接收服务器的响应。 这个错误通常意味着在 ws.recv() 尝试接收数据之前,WebSocket 连接已经意外关闭。以下将详细介绍可能的原因以及相应的解决方案。
检查 WebSocket 连接参数
首先,确保建立 WebSocket 连接时使用的参数正确无误。特别需要关注以下几个方面:
Kernel ID 和 Session ID: 确保 Kernel ID 和 Session ID 从 Jupyter Notebook API 的 /api/sessions 接口正确获取,并且在创建 WebSocket 连接时正确地拼接到 URL 中。URL 格式: WebSocket URL 的格式必须正确。正确的格式通常是 ws://127.0.0.1:8888/api/kernels//channels?session_id=。 仔细检查 URL 中是否缺少任何参数,或者参数值是否正确。Headers: 确保在创建 WebSocket 连接时传递了必要的 Headers,例如 Content-Type。
以下代码展示了如何正确地创建 WebSocket 连接:
import jsonimport requestsfrom websocket import create_connection# 获取 Session 和 Kernel 信息base = "http://127.0.0.1:8888" # 替换为你的 Jupyter Notebook 地址headers = {"Content-Type": "application/json"}file_name = "example.ipynb" # 替换为你的 Notebook 文件名notebook_path = "/" + file_nameurl = base + '/api/sessions'params = '{"path":"%s","type":"notebook","name":"","kernel":{"id":null,"name":"env37"}}' % file_nameresponse = requests.post(url, headers=headers, data=params)session = json.loads(response.text)kernel = session["kernel"]# 创建 WebSocket 连接ws_url = f"ws://127.0.0.1:8888/api/kernels/{kernel['id']}/channels?session_id={session['id']}"ws = create_connection(ws_url, header=headers)print(f"WebSocket 连接已建立:{ws_url}")# 发送执行请求(示例)code = "print('Hello, Jupyter!')"message = { "header": { "msg_id": "some-unique-id", "username": "test", "session": session["id"], "data": "2023-12-12T00:00:00.000000", # 确保包含时区信息 "msg_type": "execute_request", "version": "5.0" }, "parent_header": {}, "metadata": {}, "content": { "code": code, "silent": False, "store_history": True, "user_expressions": {}, "allow_stdin": False }, "buffers": [], "channel": "shell"}ws.send(json.dumps(message))print(f"已发送代码:{code}")# 接收响应result = json.loads(ws.recv())print(f"接收到响应:{result}")ws.close()print("WebSocket 连接已关闭")
处理时区问题
根据问题解答中的信息,message 字典中的 “data” 字段需要包含明确的时区信息。 如果时区信息缺失或格式不正确,可能会导致连接不稳定。 确保 “data” 字段包含完整的日期和时间信息,包括时区。 例如,可以使用 datetime.datetime.now(datetime.timezone.utc).isoformat() 来生成包含 UTC 时区的日期时间字符串。
实现自动重连机制
WebSocket 连接可能会因为各种原因中断,例如网络不稳定或服务器端超时。 为了提高代码的健壮性,建议实现自动重连机制。 当捕获到 WebSocketConnectionClosedException 异常时,可以尝试重新建立 WebSocket 连接。
以下代码展示了如何实现自动重连:
import timeimport jsonimport requestsfrom websocket import create_connection, WebSocketConnectionClosedExceptiondef execute_code(code, ws, session): message = { "header": { "msg_id": "some-unique-id", "username": "test", "session": session["id"], "data": "2023-12-12T00:00:00.000000", # 确保包含时区信息 "msg_type": "execute_request", "version": "5.0" }, "parent_header": {}, "metadata": {}, "content": { "code": code, "silent": False, "store_history": True, "user_expressions": {}, "allow_stdin": False }, "buffers": [], "channel": "shell" } ws.send(json.dumps(message)) print(f"已发送代码:{code}") try: result = json.loads(ws.recv()) print(f"接收到响应:{result}") return result except WebSocketConnectionClosedException as e: print(f"WebSocket 连接已关闭:{e}") return Nonedef create_websocket_connection(kernel_id, session_id, headers): ws_url = f"ws://127.0.0.1:8888/api/kernels/{kernel_id}/channels?session_id={session_id}" try: ws = create_connection(ws_url, header=headers) print(f"WebSocket 连接已建立:{ws_url}") return ws except Exception as e: print(f"无法创建 WebSocket 连接:{e}") return None# 获取 Session 和 Kernel 信息 (与前面的代码相同)base = "http://127.0.0.1:8888" # 替换为你的 Jupyter Notebook 地址headers = {"Content-Type": "application/json"}file_name = "example.ipynb" # 替换为你的 Notebook 文件名notebook_path = "/" + file_nameurl = base + '/api/sessions'params = '{"path":"%s","type":"notebook","name":"","kernel":{"id":null,"name":"env37"}}' % file_nameresponse = requests.post(url, headers=headers, data=params)session = json.loads(response.text)kernel = session["kernel"]# 创建 WebSocket 连接ws = create_websocket_connection(kernel["id"], session["id"], headers)if ws: code = "print('Hello, Jupyter!')" result = execute_code(code, ws, session) if not result: print("尝试重新连接...") ws = create_websocket_connection(kernel["id"], session["id"], headers) if ws: result = execute_code(code, ws, session) if result: print("重新连接成功并接收到响应。") else: print("重新连接后仍然无法接收响应。") else: print("无法重新建立 WebSocket 连接。") ws.close() print("WebSocket 连接已关闭")else: print("初始 WebSocket 连接失败。")
在这个示例中,execute_code 函数尝试发送代码并接收响应。 如果捕获到 WebSocketConnectionClosedException 异常,则会调用 create_websocket_connection 函数尝试重新建立连接。
总结
解决 Jupyter Notebook WebSocket “socket is already closed” 错误的关键在于:
仔细检查 WebSocket 连接参数,确保 Kernel ID、Session ID 和 URL 格式正确。确保消息中的 “data” 字段包含完整的日期和时间信息,包括时区。实现自动重连机制,以便在连接中断时自动尝试重新建立连接。
通过以上方法,可以有效地解决 WebSocket 连接关闭问题,提高代码的稳定性和可靠性。
以上就是解决 Jupyter Notebook WebSocket 连接关闭问题的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1376023.html
微信扫一扫
支付宝扫一扫