我正在开发一款基于多人回合的游戏(例如国际象棋),应该支持很多玩家(这就是想法)。我的问题是关于我正在开发的服务,它是配对系统,负责将2位玩家配对以开始一个房间并开始比赛。
因此,这是配对服务:
matchPlayers() {
if (this.players.length >= 2) {
let player1 = this.players.shift();
let player2 = this.players.shift();
if (player1 !== undefined && player2 !== undefined) {
player1.getSocket().emit('opponent_found');
player2.getSocket().emit('opponent_found');
return this.createMatchInDataBaseApiRequest(player1, player2)
.then(function (data) {
let room = new RoomClass(data.room_id, player1, player2);
player1.setRoom(room);
player2.setRoom(room);
return room;
});
}
}
return false;
}
在服务器的入口点,我将每个新的套接字连接推送到一个数组“ PlayersPool”,该数组供等待匹配的玩家使用。
现在,我的方法是在可用时配对用户(FIFO-先进先出)。
我发现此配对系统存在的问题(和疑问)是:
这取决于新用户,每次连接新用户时都会执行此操作,流程是:用户连接,将其添加到池中,并检查是否有等待配对的用户,如果是创建一个房间,他们可以玩,如果没有,他可以添加到等候池中;直到新用户连接并执行代码,依此类推...
如果在某些奇怪的情况下(不确定是否会发生这种情况)会发生什么情况(不确定是否会发生),同时在同一确切时间将2个玩家添加到等待池中,此服务将发现池中没有空间,并且不会创建房间:为了解决这个问题,也许有另一个服务一直在运行并检查池?最好的方法是什么?这可能发生吗?在哪种情况下?
感谢您的帮助。
答案 0 :(得分:1)
我猜这个特定的代码片段在服务器上?如果是这样的话,假设只有一台服务器,那么就没有“竞争条件”:如IceMetalPunk所述,node.js是单线程的,因此,如果您每次在{{1} },你应该没事。
有其他原因定期检查玩家池,但是:您添加到玩家池中的玩家可能已断开连接(由于超时或关闭浏览器),因此您应该删除他们;您还可能需要处理玩家等待了很长时间的情况-X秒后,您是否应该在更新进度的玩家,为他们计算估计的等待时间,或者在等待时生成AI玩家进行交互等
答案 1 :(得分:1)
您可能会遇到“竞赛条件”,在此软件包中对此进行了说明,该软件包为您提供了一种锁定机制。 https://github.com/puma/puma
仅当您在单个进程中运行node.js(即您没有多个服务器或节点集群运行多个进程)时,该软件包才有用。
在那种情况下,您将必须实现分布式锁定机制,这是分布式计算中最复杂的事情之一,但是今天您可以使用Redpm算法的npm软件包,设置3个redis服务器并运行。 没有玩家的游戏开销太大。
Node.js不是单线程的,这是其中一个创建者的说明。
早晨主题演讲-您需要了解的有关Node.js事件循环的所有内容-Bert Belder,IBM
https://www.npmjs.com/package/async-lock
结论,简单起见,在单个节点进程中运行它,并使用“ async-lock”包。
如果您的服务器逐渐成为MMO,则需要阅读有关分布式计算的信息: 如何进行分布式锁定: https://www.youtube.com/watch?v=PNa9OMajw9w
预订数据密集型应用 https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html