Flask-Socketio数据流15分钟后断开客户端,重连后推送失效求助
Flask-SocketIO 闲置15分钟后重连但数据流中断问题解决思路
问题现象
基于Flask+SocketIO+Eventlet构建的实时流Web应用,Chrome网页闲置约15分钟后,Web客户端和Python SocketIO客户端均收到断开连接事件;重连成功后,UI数据流完全停止更新。部署环境为IIS管理器。
核心流程回顾
DataStreamer.py(Python SocketIO客户端)→ 从外部WebSocket获取数据处理后,通过/web命名空间发送mydata事件到服务器 → 服务器更新Curve全局字典 → Web客户端加载时发送be事件触发后台任务CalculateBE,该任务每隔5秒计算Curve数据并通过bedata事件推送到UI → UI更新表格。
问题根源分析
- IIS进程回收+心跳配置不匹配:IIS默认15-20分钟闲置进程回收机制会重启Flask应用;当前
ping_timeout=15过短,客户端与服务器心跳检测逻辑误判连接失效。 - 后台任务绑定失效:原后台任务绑定在旧连接实例上,重连后未重新触发任务,数据推送通道中断。
- 命名空间与重连逻辑错误:Web客户端未指定
/web命名空间,重连后无法订阅事件;DataStreamer可能在连接未完全建立时发送事件,触发命名空间未连接错误。 - 线程锁未实例化:
thread_lock = Lock未创建实例,导致后台任务线程安全控制失效,无法正确重启任务。
具体解决步骤
1. 调整IIS进程回收设置(关键)
- 打开IIS管理器,找到对应应用池→高级设置
- 禁用闲置超时(或延长至480分钟以上)
- 禁用定期回收(或调整至低峰期)
- 设置启动模式为
AlwaysRunning,避免应用被闲置回收
2. 优化SocketIO心跳配置
修改__init__.py中的SocketIO初始化参数:
# __init__.py from flask import Flask from flask_socketio import SocketIO from threading import Lock import eventlet eventlet.monkey_patch() app = Flask(__name__, template_folder='./templates') app.config['SECRET_KEY'] = 'privatekey!' thread = None thread_lock = Lock() # 修复:实例化Lock socketio = SocketIO(app, cors_allowed_origins='*', ping_timeout=60, # 延长超时时间,避免误判 ping_interval=25, # 每25秒发送心跳 logging=True)
3. 修复后台任务与重连触发逻辑
修改MydataClient.py,确保重连后自动重启任务:
# MydataClient.py from wwwroot.StreamingApp import app, thread, thread_lock, socketio Curve = None live_be = [] # 确保全局变量初始化 def CalculateBE(): while True: response = {'status': True} for args in live_be: if args is None: continue be_price = 0 # 替换为你的计算逻辑 response['BE' + str(args[0])] = be_price # 指定命名空间发送,确保所有/web客户端接收 socketio.emit('bedata', response, namespace='/web') socketio.sleep(5) @socketio.on('be', namespace='/web') def UpdateBE(): global thread with thread_lock: # 检查任务是否存活,不存在则启动 if thread is None or not thread.is_alive(): thread = socketio.start_background_task(CalculateBE) # 新增:web命名空间连接时自动触发任务 @socketio.on('connect', namespace='/web') def on_web_connect(): UpdateBE()
4. 修正Web客户端命名空间与重连逻辑
修改client.html中的JS代码,指定命名空间并在重连后重新触发任务:
<script> $(document).ready(function () { // 明确连接/web命名空间 var flask_socket = io.connect('http://localhost:90/web'); flask_socket.on('connect', () => { console.log('connected!'); // 重连后重新触发后台任务 flask_socket.emit('be'); }); flask_socket.on('disconnect', () => { console.log('disconnected!'); }); flask_socket.on("bedata", function (response) { // 你的UI更新逻辑 console.log('Received bedata:', response); }); }); </script>
5. 优化DataStreamer重连事件发送逻辑
确保DataStreamer在连接完全建立后发送事件:
# DataStreamer.py import socketio def on_connect(): print("Connected to server") def on_disconnect(): print("Disconnected from server") def on_reconnect(): print("Reconnected to server") sio = socketio.Client(reconnection_attempts=5, reconnection_delay=2, reconnection_delay_max=10) sio.on('connect', on_connect) sio.on('disconnect', on_disconnect) sio.on('reconnect', on_reconnect) # 连接指定命名空间 sio.connect('http://localhost:90', namespaces=['/web']) # 在连接事件回调中处理数据发送,确保连接就绪 @sio.event(namespace='/web') def connect(): # 替换为你的数据获取与处理逻辑 curve_data = {} sio.emit("mydata", curve_data, namespace="/web") # 循环发送数据前检查连接状态 while True: if sio.connected and '/web' in sio.namespaces: curve_data = {} # 实际数据 sio.emit("mydata", curve_data, namespace="/web") sio.sleep(1)
验证步骤
- 重启IIS应用池和Flask服务
- 打开Web UI并保持闲置超过15分钟
- 检查客户端日志,确认重连后UI能正常接收
bedata更新 - 检查DataStreamer日志,确保重连后无命名空间错误,
mydata事件正常发送
内容的提问来源于stack exchange,提问作者Yash
相关产品推荐
相关产品推荐

