如何用 Socket.IO 实现实时多人对战:GameHub.io 的 join、new-move、resign 事件流全拆解
如何用 Socket.IO 实现实时多人对战GameHub.io 的 join、new-move、resign 事件流全拆解【免费下载链接】gamehub.ioReal-time multiplayer game server based on Node Express SocketIO MongoDB ElasticSearch项目地址: https://gitcode.com/gh_mirrors/ga/gamehub.ioGameHub.io 是一个基于Node.js Express Socket.IO MongoDB ElasticSearch的开源实时多人游戏服务器用最简洁的代码实现了完整的双人对战流程。本文以它内置的象棋对局为场景手把手拆解join加入对局、new-move走棋广播、resign认输清理这 3 个核心事件是如何让两台浏览器零刷新实时互动的新手也能快速上手实时多人开发。 项目概览实时对战服务器长什么样GameHub.io 的架构非常清晰前后端各承担自己的职责层技术作用Web 框架Express页面路由、登录注册实时通信Socket.IOjoin / new-move / resign 事件流持久化MongoDB Mongoose用户、对局记录搜索ElasticSearch对局索引与检索前端jQuery Chess.js Chessboard.js棋盘渲染与走棋合法性校验整个服务的启动入口在 app.js第 62 行创建 HTTP 服务并监听 3000 端口第 64 行把服务交给 Socket.IO 配置模块var server require(http).createServer(app).listen(3000); require(./config/socket.js)(server);也就是说所有实时对战逻辑都集中在一个文件里config/socket.js不到 160 行这也是本文拆解的主角。 事件流全景一张图看懂 join、new-move、resign官方给出的简化时序图覆盖了从建房到对局结束的全部关键事件完整流程分 4 步建房玩家发起对局服务器生成一个 20 位随机 token 作为房间号对局令牌加入join房主把链接发给对手双方凭 token 加入同一个 Socket.IO 房间room走棋new-move对局开始后每一步棋由服务器转发给对手结束resign一方认输或掉线服务器通知对手并清理房间下面逐一拆解每个事件的前后端代码。 事件一join —— 凭 Token 进入对战房间房主侧生成 token 并等待对手用户点击开始对局后routes/play.jsL13-L18会用config/util.js里的randomString(20)生成一个 20 位随机 token然后重定向到对局页/play → 生成 token → 302 重定向到 /game/:token/:sideroutes/index.jsL31-L41渲染对局页时把token和side执白/执黑写进页面数据属性供前端 JavaScript 读取。前端页面加载即发送 join前端在public/javascripts/chesshub.jsL248-L251建立 Socket.IO 连接后页面一加载就发出join事件携带 token 和自己的阵营socket.emit(join, { token: token, side: side });服务端第一个 join 建房第二个 join 开局config/socket.jsL58-L101的join处理器用一个内存字典games {}管理所有房间逻辑分两支第一个玩家房主token 还不存在于是创建房间记录status: waiting把自己加入房间并向房主回发wait事件——前端收到后弹出等待对手弹窗展示邀请链接chesshub.jsL256-L263第二个玩家把 socket 加入同一个 room把game.status置为ready然后对整个房间广播ready事件带上双方名字L99 关键设计Socket.IO 的room房间机制是多人对战的核心。socket.join(room)之后io.sockets.to(room)就能把消息精准投递给房内所有玩家天然实现了只推给对局双方。前端收到readychesshub.jsL268-L276后填充双方玩家名、启动计时器、关闭等待弹窗——对局正式开始。♟️ 事件二new-move —— 一步棋如何毫秒级送达对面这是整个事件流中最精彩的部分服务器只做中继不做校验。走棋方在棋盘上拖拽棋子后Chess.js 先在本地校验走法是否合法非法则 snapback 弹回L200-L221合法才发出事件socket.emit(new-move, { token: token, source: source, target: target, piece: piece, newPosition: ..., oldPosition: ... });服务端只有一行核心逻辑config/socket.jsL106-L108socket.on(new-move, function(data) { socket.broadcast.to(data.token).emit(new-move, data); });注意broadcast的用法它只转发给房间内其他socket走棋者自己不需要收到。对手方收到new-movechesshub.jsL281-L287后用 Chess.js 回放这步棋并刷新棋盘位置、PGN 记录socket.on(new-move, function(data) { game.move({ from: data.source, to: data.target }); board.position(game.fen()); });⚠️ 新手提示这个 demo 把走棋合法性校验放在客户端Chess.js便于理解实时同步原理生产级对战服务器应在服务端二次校验防止恶意客户端伪造走法。️ 事件三resign —— 认输、断线与战场清理对局结束时资源清理和状态通知同样重要。主动认输点击对局页的 Resign 按钮页面模板见views/partials/game.hbsL33前端发出resign事件。服务端处理config/socket.jsL113-L124做四件事向整个房间广播player-resigned带上认输方阵营让双方 socket 离开该 roomdelete games[room]删除房间记录释放内存通知监控命名空间刷新当前对局数对手端收到player-resignedchesshub.jsL303-L309后弹出Game Over结果弹窗。意外断线disconnect处理器L129-L143遍历所有房间发现掉线者后向其对手广播opponent-disconnected并同样删除房间。两条路径保证了房间状态不会泄漏。 加餐/tv 与 /monitor 命名空间除了主对战连接config/socket.js还演示了 Socket.IO 的**命名空间namespace**用法io.of(/tv)L12每 3 秒自动走一步随机棋把 FEN/PGN 推送给首页和 TV 页实现直播围观io.of(/monitor)L40广播在线人数与对局数驱动监控看板实时刷新一个 Node 进程同时管理 3 条独立消息通道互不干扰——这是命名空间隔离的价值。 快速上手跑起来你的第一个实时对战前置依赖MongoDB27017与 ElasticSearch9200或直接用项目自带的 docker-compose.yml 一键拉起三个容器mongo elasticsearch chesshub。启动步骤npm installbower install安装前后端依赖node initData.js向 MongoDB / ElasticSearch 灌入演示数据node .启动服务浏览器访问http://localhost:3000注册账号或用内置账号foobar.org / foobar登录后点击 Play把弹出的对局链接发给另一台浏览器——打开即可实时对弈。相关配置见config/default.jsonDocker 说明见 README.md。✅ 总结3 条带走的实时多人开发心得Room 是多人对战的地基join事件本质是把 socket 组织进房间之后一切广播都靠to(room)服务端只做最小必要逻辑new-move 一行转发、resign 三步清理demo 代码 160 行内讲清完整生命周期断线必须兜底disconnect与resign走同一套清理路径是房间状态不泄漏的关键想深入更多细节可重点阅读config/socket.js服务端事件、public/javascripts/chesshub.js客户端事件与routes/index.js对局页路由这三个文件。【免费下载链接】gamehub.ioReal-time multiplayer game server based on Node Express SocketIO MongoDB ElasticSearch项目地址: https://gitcode.com/gh_mirrors/ga/gamehub.io创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考