Flask-SocketIO join_room功能异常:加入房间后在线数始终为0
解决Flask-SocketIO join_room后房间Socket数量显示为0的问题
问题场景
用Flask做后端、React做前端开发在线游戏大厅时,调用Flask-SocketIO的join_room方法后,打印房间内Socket数量始终显示为0,无法正确判断房间人数。
前端app.js连接代码
class SocketService { socket; connect(url) { return new Promise((rs, rj) => { this.socket = io(url); if (!this.socket) return rj(); this.socket.on("connect", () => { rs(this.socket); }); this.socket.on("connect_error", (err) => { console.log("Connection error: ", err); rj(err); }); }); } } const connectSocket = async () => { await socketService .connect("http://localhost:5001") .catch((err) => { console.log("Error: ", err); }); }; useEffect(() => { connectSocket(); }, []);
后端app.py代码
from flask import Flask, send_from_directory, json from flask_restful import Api from flask_cors import CORS from flask_socketio import SocketIO, rooms, join_room, send app = Flask(__name__, static_url_path='', static_folder='client/build') CORS(app, resources={r"/*": {"origins": "*"}}) api = Api(app) SOCKETIO = SocketIO(app, cors_allowed_origins="*", json=json, manage_session=True, logger=True, engineio_logger=True) @SOCKETIO.on('join_game') def joinGame(message): connectedSockets = rooms(message['roomId']) print('Received join game request to room:', message['roomId']) print('Number of sockets in this room:', len(connectedSockets)) if len(connectedSockets) >= 2: SOCKETIO.emit("room_join_error", { 'error': "Room is full! Please choose another room to play." }) else: roomId = message['roomId'] join_room(roomId) print("A user joined this room: ", roomId) print("Number of users in room after joining: ", len(rooms(roomId))) send("A new user has joined this room.", to=roomId) SOCKETIO.emit("room_joined") if (len(connectedSockets) == 2): SOCKETIO.emit("start_game", { 'start': True, 'symbol': "X" }) SOCKETIO.to(message['roomId']).emit("start_game", { 'start': False, 'symbol': "O" }) if __name__ == "__main__": SOCKETIO.run( app=app, port=5001, debug=True )
问题根源
rooms()函数用法错误:原代码中rooms(message['roomId'])无法正确获取房间内的Socket列表。在Flask-SocketIO的事件处理函数中,rooms()不传参数时返回当前客户端已加入的所有房间;传入参数并非用于获取房间内客户端,而是判断客户端是否在指定房间。- 房间名前缀问题:Flask-SocketIO默认会给房间名添加
/前缀,直接用传入的roomId查询会找不到对应的房间。
修复方案
1. 修正房间内Socket数量的获取逻辑
替换原代码中获取房间连接数的部分,改用服务器管理器查询房间:
# 获取房间内客户端数量,需添加默认的/前缀 room_key = f"/{message['roomId']}" connected_sockets = SOCKETIO.server.manager.rooms.get(room_key, []) print('Number of sockets in this room:', len(connected_sockets))
2. 调整完整的事件处理逻辑
from flask import request # 需添加此导入 @SOCKETIO.on('join_game') def joinGame(message): roomId = message['roomId'] room_key = f"/{roomId}" connected_sockets = SOCKETIO.server.manager.rooms.get(room_key, []) print('Received join game request to room:', roomId) print('Number of sockets in this room:', len(connected_sockets)) if len(connected_sockets) >= 2: # 只给当前请求的客户端发送错误信息 SOCKETIO.emit("room_join_error", { 'error': "Room is full! Please choose another room to play." }, to=request.sid) else: join_room(roomId) # 重新获取更新后的房间连接数 updated_connected_sockets = SOCKETIO.server.manager.rooms.get(room_key, []) print("A user joined this room: ", roomId) print("Number of users in room after joining: ", len(updated_connected_sockets)) send("A new user has joined this room.", to=roomId) # 只给当前客户端发送加入成功通知 SOCKETIO.emit("room_joined", to=request.sid) # 当房间人数变为2时触发游戏开始 if len(updated_connected_sockets) == 2: # 给房间内另一个客户端发送X角色 SOCKETIO.to(roomId).emit("start_game", { 'start': True, 'symbol': "X" }, skip_sid=request.sid) # 给当前客户端发送O角色 SOCKETIO.emit("start_game", { 'start': False, 'symbol': "O" }, to=request.sid)
3. 前端补充事件发送与监听
确保连接成功后正确发送join_game事件并监听后端响应:
const connectSocket = async () => { try { const socket = await socketService.connect("http://localhost:5001"); // 替换为实际的房间ID socket.emit('join_game', { roomId: 'your-room-id' }); socket.on('room_joined', () => { console.log('成功加入房间'); }); socket.on('room_join_error', (err) => { console.error('加入房间失败:', err.error); }); socket.on('start_game', (data) => { console.log('游戏开始,你的角色:', data.symbol); }); } catch (err) { console.log("连接出错: ", err); } };
额外注意事项
- 版本兼容:确保Flask-SocketIO和前端
socket.io-client版本匹配(如Flask-SocketIO 5.x对应socket.io-client 4.x)。 - 精准推送:使用
request.sid定位当前客户端,避免事件广播给所有用户。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

