Python端检测到Socket.io连接,但JavaScript客户端无事件触发
Flask-SocketIO连接成功但前端无响应的问题修复
核心问题分析
你的代码存在两个关键问题导致前端无法收到事件:
- 事件线程阻塞:在
handle_connect中直接调用start_sending,而该函数是无限循环逻辑,会占用整个SocketIO事件线程,导致后续消息推送、事件处理完全卡住。 - 双重循环冗余:
get_screen本身已包含while True的生成器逻辑,start_sending又嵌套循环遍历生成器,造成逻辑混乱且推送效率低下。
解决方案
1. 用后台任务启动推送逻辑
Flask-SocketIO要求事件处理函数不能长时间阻塞,必须通过socketio.start_background_task将循环/耗时任务放到后台线程执行,避免占用主事件循环。
2. 简化屏幕捕获逻辑
移除get_screen中的无限循环,让它单次调用返回单帧数据,在start_sending中控制推送频率,逻辑更清晰。
3. 确保前后端版本兼容
前端使用SocketIO JS 4.6.0,需对应后端安装Flask-SocketIO 5.x及以上版本,执行命令更新:
pip install flask-socketio>=5.0.0
4. 优化前端连接代码
页面从服务器渲染时,无需手动指定URL,直接用io()即可自动连接当前服务器,提升代码灵活性。
修改后的完整代码
server.py
from flask import Flask, render_template from flask_socketio import SocketIO, emit from flask_cors import CORS import pyautogui import cv2 import numpy as np import base64 app = Flask(__name__) CORS(app) socketio = SocketIO(app, cors_allowed_origins="*") # 初始化全局变量 stop_stream = False @app.route('/') def index(): return render_template("index.html") def get_screen(): # 单次捕获屏幕并返回编码后的字符串 screenshot = pyautogui.screenshot() frame = np.array(screenshot) frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) _, jpeg = cv2.imencode('.jpg', frame) encoded_img = base64.b64encode(jpeg.tobytes()) return encoded_img.decode('utf-8') @socketio.on('connect') def handle_connect(): print('Client connected') # 用后台任务启动推送,避免阻塞事件循环 socketio.start_background_task(start_sending) def start_sending(): global stop_stream stop_stream = False while not stop_stream: frame = get_screen() emit('image', frame) socketio.sleep(0.1) # 控制推送频率,避免过高占用资源 @socketio.on('disconnect') def handle_disconnect(): global stop_stream stop_stream = True print('Client disconnected') @socketio.on_error_default def default_error_handler(e): print('An error occurred:', e) if __name__ == '__main__': socketio.run(app, host='0.0.0.0', port=5000, debug=True)
templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Stream Viewer</title> <script src="https://cdn.socket.io/4.6.0/socket.io.min.js" integrity="sha384-c79GN5VsunZvi+Q/WObgk2in0CbZsHnjEqvFxC5DxHn9lTfNce2WW6h2pH6u/kF+" crossorigin="anonymous"></script> </head> <body> <img id="screenFrame" style="max-width: 100%;"> <script> // 自动连接当前服务器,无需手动指定URL var socket = io(); socket.on('connect', function(){ console.log('连接成功!'); }); socket.on('disconnect', function(){ console.log('连接断开!'); }); socket.on('error', function(err){ console.log('Socket错误:', err); }); socket.on('image', data => { console.log("收到图像数据"); const img = document.getElementById('screenFrame'); img.src = 'data:image/jpeg;base64,' + data; }); </script> </body> </html>
验证步骤
- 确保安装符合版本要求的Flask-SocketIO:
pip install flask-socketio>=5.0.0 - 启动服务器:
python server.py - 访问
http://localhost:5000,打开浏览器控制台查看日志 - 此时应能看到“连接成功!”日志,页面同时显示屏幕流
内容的提问来源于stack exchange,提问作者MaikeruDev
相关产品推荐
相关产品推荐

