Socket.io双人游戏开发:无需存储socket.id检测用户房间状态
无需数据库存储Socket.id实现双人游戏房间匹配方案
核心思路:服务器端维护在线用户内存映射
不用数据库存socket.id,而是在服务器端用**内存数据结构(比如Map)**实时维护在线用户的用户名与房间ID/ Socket实例的映射,因为用户在线时才需要这个关联,离线即可清理,完全满足实时匹配需求。
具体实现步骤
1. 初始化在线用户映射
在服务器端创建一个Map,用于存储已上线玩家的用户名和对应的房间信息:
// 服务器端代码 const onlineUsers = new Map(); // 键:玩家用户名(需保证唯一) // 值:{ roomId: 房间ID, socket: 当前玩家的socket实例 }
2. 第一个玩家上线逻辑
玩家连接后,发送自己的用户名到服务器,服务器为其创建房间(可直接用用户名或socket.id作为房间名),并将信息存入Map:
io.on('connection', (socket) => { // 监听玩家上线事件 socket.on('player-online', (username) => { // 检查用户名是否已被在线玩家占用 if (onlineUsers.has(username)) { socket.emit('username-duplicate', '该用户名已在线'); return; } // 用用户名作为房间名(更直观,无需额外存储roomId) const roomId = username; socket.join(roomId); // 存入在线用户映射 onlineUsers.set(username, { roomId, socket }); // 通知玩家等待对手 socket.emit('waiting', '等待对手加入...'); });
3. 第二个玩家匹配房间逻辑
第二个玩家输入目标用户名后,服务器查询Map:如果存在该用户,直接让当前玩家加入对应的房间,并触发游戏开始事件:
// 监听玩家请求加入对手房间的事件 socket.on('join-opponent', (targetUsername, currentUsername) => { const targetPlayer = onlineUsers.get(targetUsername); if (!targetPlayer) { socket.emit('opponent-not-found', '目标玩家未上线'); return; } // 加入目标玩家的房间 socket.join(targetPlayer.roomId); // 通知房间内所有玩家游戏开始 io.to(targetPlayer.roomId).emit('game-start', { player1: targetUsername, player2: currentUsername }); // 从映射中移除这两个玩家,避免重复匹配 onlineUsers.delete(targetUsername); onlineUsers.delete(currentUsername); });
4. 处理玩家离线场景
当玩家断开连接时,及时从Map中删除其信息,并通知可能在等待的对手:
// 监听玩家断开连接事件 socket.on('disconnect', () => { // 找到当前玩家对应的用户名并删除 for (const [username, playerData] of onlineUsers.entries()) { if (playerData.socket.id === socket.id) { onlineUsers.delete(username); // 通知房间内的对手玩家 io.to(playerData.roomId).emit('opponent-left', '对手已断开连接'); break; } } }); });
原思路的误区说明
你之前把socket.id存入数据库的做法存在两个核心问题:
- socket.id是临时值:玩家刷新页面、重新连接都会生成新的socket.id,数据库中存储的旧ID会立即失效,还需要额外的更新逻辑,完全没必要。
- 实时性差:数据库无法实时感知玩家离线状态,容易出现匹配到已离线玩家的情况,而内存映射可以在玩家断开时立即清理数据,保证匹配的准确性。
额外注意事项
- 用户名唯一性:必须保证玩家的用户名是全局唯一的(可在注册阶段校验),否则会出现在线用户映射被覆盖的问题。
- 多服务器部署场景:如果你的服务需要集群部署,单服务器的内存Map无法共享,此时可以用Redis等分布式缓存来替代内存Map,实现跨服务器的在线用户状态共享。
内容的提问来源于stack exchange,提问作者user14436230
相关产品推荐
相关产品推荐

