树莓派Zero上Flask-socketIO无法工作问题求助
问题分析与解决方案
你的核心问题是后端SocketIO事件处理函数被阻塞,导致无法正常处理WebSocket连接和数据推送,同时前端存在重复创建Socket实例的问题,具体修复如下:
后端(MPU9250.py)修复
@socketio.on('connect')中的while True+time.sleep(0.1)会完全阻塞SocketIO的事件循环,使得服务器无法响应新的连接请求,也无法推送数据。必须改用SocketIO的后台任务来处理持续的数据采集和推送:
from flask import Flask, render_template from flask_socketio import SocketIO, emit import smbus import time app = Flask(__name__) app.config['SECRET_KEY'] = 'secret!' async_mode = 'eventlet' socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode) ### SENSOR CODE HERE(确保read_word_2c等函数已正确实现) # 定义后台任务,负责持续采集并推送数据 def sensor_stream_task(): while True: # 读取传感器数据 accel_xout = read_word_2c(accel_xout_h) accel_yout = read_word_2c(accel_yout_h) accel_zout = read_word_2c(accel_zout_h) mag_xout = read_word_2c(mag_xout_h) mag_yout = read_word_2c(mag_yout_h) mag_zout = read_word_2c(mag_zout_h) print("X Accel: ", accel_xout, " | Y Accel: ", accel_yout, " | Z_Accel: ", accel_zout) # 推送数据到客户端 socketio.emit('acceleration', {'x': time.time(), 'y': accel_xout}) socketio.emit('magnetometer', {'x': time.time(), 'y': mag_xout}) socketio.send('Test message') # 使用SocketIO的sleep,避免阻塞事件循环 socketio.sleep(0.1) @app.route('/') def index(): return render_template('index.html') # 客户端连接时启动后台任务 @socketio.on('connect') def handle_connect(): print('Client connected') # 启动后台任务,每个连接可以单独启动或共享,这里按需求选择 socketio.start_background_task(sensor_stream_task) if __name__ == '__main__': socketio.run(app, debug=True, port=80, host='0.0.0.0')
关键修改:
- 将数据采集逻辑移到独立的后台任务函数
sensor_stream_task中 - 使用
socketio.start_background_task()启动任务,而非阻塞事件处理函数 - 用
socketio.sleep(0.1)替代time.sleep(0.1),保证事件循环正常运行
前端(index.html)修复
前端重复创建了io()实例,会导致多个WebSocket连接冲突,合并Socket实例并精简代码:
<!DOCTYPE html> <html> <head> <title>MPU9250 Sensor Data</title> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js" integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ==" crossorigin="anonymous"></script> </head> <body> <h1>MPU9250 Sensor Stream</h1> <h2>Acceleration</h2> <div id="acceleration-graph"></div> <h2>Magnetometer</h2> <div id="magnetometer-graph"></div> <script type="text/javascript" charset="utf-8"> console.log("Page loaded"); // 初始化图表数据和布局 const accelerationData = { x: [], y: [], mode: "lines", name: "Acceleration", }; const magnetometerData = { x: [], y: [], mode: "lines", name: "Magnetometer", }; const accelerationLayout = { title: "Acceleration Data", xaxis: { title: "Time" }, yaxis: { title: "Acceleration (raw)" }, }; const magnetometerLayout = { title: "Magnetometer Data", xaxis: { title: "Time" }, yaxis: { title: "Magnetic field (raw)" }, }; const accelerationPlot = Plotly.newPlot( "acceleration-graph", [accelerationData], accelerationLayout ); const magnetometerPlot = Plotly.newPlot( "magnetometer-graph", [magnetometerData], magnetometerLayout ); // 只创建一个Socket实例 var socket = io(); socket.on("connect", function () { console.log("Connected to server"); socket.emit("my_event", { data: "I'm connected!" }); }); // 监听加速度数据 socket.on("acceleration", function (data) { console.log('X_Accel: ' + data.x, 'Y_Accel: ' + data.y); accelerationData.x.push(data.x); accelerationData.y.push(data.y); Plotly.update("acceleration-graph", [accelerationData], accelerationLayout); }); // 监听磁力计数据 socket.on("magnetometer", function (data) { console.log('X_Mag: ' + data.x, 'Y_Mag: ' + data.y); magnetometerData.x.push(data.x); magnetometerData.y.push(data.y); Plotly.update("magnetometer-graph", [magnetometerData], magnetometerLayout); }); // 监听测试消息 socket.on('message', function(msg) { console.log('Test message: ' + msg); }); </script> </body> </html>
关键修改:
- 删除重复的
$(document).ready中的Socket实例创建,只保留一个全局Socket实例 - 优化日志输出,方便调试
- 新增对
message事件的监听,接收后端的测试消息
额外注意事项
- 确保已安装
eventlet:pip install eventlet,因为你指定了async_mode='eventlet',必须安装对应的异步引擎 - 传感器代码中的
read_word_2c、accel_xout_h等变量/函数必须正确实现,否则会抛出异常导致后台任务终止 - 如果多个客户端连接,当前代码会为每个客户端启动一个后台任务,若需要共享数据推送,可以改为全局后台任务(启动一次即可)
内容的提问来源于stack exchange,提问作者G.H.
相关产品推荐
相关产品推荐

