Node.js Socket.io游戏开发:如何逐个接收客户端确认请求?
解决Socket.io客户端同时发送ACK导致重复创建游戏的问题
这个问题我之前做多人游戏的时候也遇到过!核心问题就是多个客户端同时发送winner_res_ack确认消息,导致create_game()被重复调用。下面给你两种解决方案,你可以根据实际需求选择:
方案一:标记游戏创建状态(最适合你的场景)
因为你只需要在所有客户端确认胜者后创建一次新游戏,所以我们可以给每个游戏房间维护一个“是否正在创建新游戏”的状态,避免重复触发。
实现代码
// 用Map按游戏ID维护创建状态,key是game_id,value是布尔值表示是否正在创建 const gameCreationStatus = new Map(); socket.on('winner_res_ack', function(game_id) { // 检查当前游戏是否已经在创建新游戏了 if (gameCreationStatus.get(game_id)) { return; // 已经在创建,直接忽略后续的ACK请求 } // 标记为正在创建 gameCreationStatus.set(game_id, true); // 执行创建游戏的函数 create_game() .then(() => { // 新游戏创建完成,重置状态,允许下次触发 gameCreationStatus.set(game_id, false); }) .catch((error) => { // 即使创建出错,也要重置状态,避免后续请求一直被阻塞 console.error('创建新游戏失败:', error); gameCreationStatus.set(game_id, false); }); });
注意点
- 如果
create_game()是同步函数,可以去掉then/catch,直接在执行完create_game()后重置状态。 - 一定要按
game_id维护状态,不然多个游戏房间的状态会互相干扰。
方案二:用异步队列逐个处理请求(适合需要逐个响应每个客户端ACK的场景)
如果你确实需要逐个处理每个客户端的ACK请求(比如每个客户端的ACK需要执行不同的逻辑),可以给每个游戏房间维护一个任务队列,确保任务逐个执行,不会并行触发。
实现代码
// 用Map按游戏ID维护请求队列,key是game_id,value是待执行的任务数组 const gameRequestQueues = new Map(); socket.on('winner_res_ack', function(game_id) { // 获取当前游戏的队列,不存在则创建新队列 let queue = gameRequestQueues.get(game_id); if (!queue) { queue = []; gameRequestQueues.set(game_id, queue); } // 将当前ACK对应的处理任务加入队列 queue.push(async () => { await create_game(); // 如果每个客户端的ACK需要额外逻辑,可以在这里添加 }); // 如果队列里只有当前这一个任务,立即开始执行队列 if (queue.length === 1) { processGameQueue(game_id); } }); // 递归处理队列的函数 async function processGameQueue(game_id) { const queue = gameRequestQueues.get(game_id); if (!queue || queue.length === 0) return; // 取出队列第一个任务执行 const currentTask = queue.shift(); try { await currentTask(); } catch (error) { console.error('处理队列任务失败:', error); } // 递归处理下一个任务 processGameQueue(game_id); }
注意点
- 这个方案会让
create_game()按客户端发送ACK的顺序逐个执行,适合需要串行处理的场景。 - 如果你的场景只需要创建一次新游戏,方案一的效率更高,不需要维护队列。
内容的提问来源于stack exchange,提问作者harsha ambadkar
相关产品推荐
相关产品推荐

