插座内部

时间:2018-07-11 19:03:44

标签: javascript node.js websocket socket.io

我希望服务器仅在客户端在另一个套接字上发送消息之后才开始侦听来自客户端的某个套接字。我试图像这样编写我的代码:

socket.on('listentome', function() {
   socket.on('actualmessage', function() {
     ...
   });
});

但是它不起作用。有什么建议吗?

3 个答案:

答案 0 :(得分:1)

最简单的解决方案是保持状态,该状态可以让您知道是否正在等待第二个事件。

let waiting = false;

socket.on('listentome', () => waiting = true);

socket.on('actualmessage', () => {
  if (!waiting) return; // if we're not waiting for this event, ignore it

  waiting = false;
  ...
});

答案 1 :(得分:0)

因此,您建议的设计:

socket.on('listentome', function() {
   socket.on('actualmessage', function() {
     ...
   });
});

实际上只是一个糟糕的设计,充满了问题。这里是一些问题:

  1. 每次您收到listentome消息时,都会为actualmessage添加另一个事件处理程序,除非您在触发它们后将其删除,否则它们会累积并处理每个收到的{{ 1}}不止一次。

  2. 事件驱动的体系结构(socket.io是)不太适合有状态的消息序列,这是您对这些序列消息提出的建议。实际上,要可靠地编程,就需要一堆额外的代码。确实最好将设计固定为不要求这样做,并且与事件驱动的体系结构更兼容。

  3. 如果同时有多个actualmessagelistentome序列在飞行中,您将无法确定哪个actualmessage消息属于哪个{{ 1}}第一条消息以及上述前两个问题的任何解决方案都可能使第一个到达的消息加倍处理,而根本不处理第二个问题。因此,如果您同时有多个actualmessage序列在运行中,那么该体系结构将根本无法工作(这本质上是一个并发问题)。

那么,如何解决这个问题?您没有为我们要解决的实际问题提供很多背景信息,而是让我们帮助您重新设计,但我会尽可能给您提供很多想法。

首先,在事件驱动的体系结构中,您通常希望一次安装事件处理程序,以使它们始终存在。然后,您可以使用状态来决定消息到达时的处理方式。

第二,您宁愿根本不需要服务器上的请求之间的状态来执行某些操作。因此,您宁愿发送的任何请求都完全完成,因此您不需要一系列事件来完成某件事。打个比方,使用http POST时,您不会一次在单独的请求中发送表单的每个字段,然后以某种方式告诉服务器您已完成并使其处理所有事情。相反,您收集了需要发送的所有内容,并通过一个http POST发送,服务器处理了所有内容并发送了一个响应。一切都是无状态的,而且要简单得多。

  

我正在创建一个多人游戏,用户可以成对玩。服务器为每个用户分配一个唯一的ID,然后将其发送给每个用户,并必须将其包括在每个套接字发射中以进行验证(以避免黑客入侵)。当用户排队时,他们发送一条消息(第一个socket.on),其中包含其ID等。当与用户配对时(如果用户已经在等待,则会立即发生,因此嵌套socket.on),他们必须进入游戏,只有这样,我才能启动玩家动作等的监听器(第二个socket.on)。

您没有向我们显示您的实际代码,但是,当用户首次连接并让每个处理程序在一个位置调用一个通用函数时,只需在套接字上添加各种侦听器以进行玩家的移动等可能会更简单。处理程序的开始,用于检查套接字是否在游戏中有效连接。如果没有,则什么也不做。如果是这样,请处理该消息。然后,您可以在首次连接套接字时安装所有事件处理程序一次。

您甚至可以抽象该内容:

listentome

而且,该方法的实现将如下所示:

listentome

然后,只要将套接字加入游戏或从游戏中删除套接字,就只需维护 socket.onWhenInGame('someGameMessage', function(data) { // this will only get called when connected in a game }); 标志。而且,您可以使用 socket.onWhenInGame = function(msg, fn) { return socket.on('msg', function(data) { if (!this.inGame) { // not in a game, ignore this message return; } else { fn(msg, data); } }); }; 进行编程,而不必担心上述所有问题。

答案 2 :(得分:0)

我一切顺利,这是我的代码。请注意,playerMovementListener函数是一个安装八个socket.on-s的函数,该函数仅在播放器发送其ID和动作时监听该播放器。

io.on('connection', function(socket) {
    //generate a user ID//
    var userID = makeID();
    //check if user is trying to connect from the same IP... if so send them out//
    for(var i = 0; i < users.length; i++) {
        if(users[i].IP == socket.handshake.address) {
            io.sockets.emit(socket.id, 'You can only play one instance of the game!');
            return;
        }
    }
    //send the user's ID to the user//
    io.sockets.emit(socket.id, userID);
    //add the users to the array of connected users//
    users.push({
        'IP' : socket.handshake.address,
        'ID' : userID,
    });
    //if user queues up for game (they send their ID when they queue up)...
    //it is wise to check if their ID exists in the list of connected users to avoid DDOS, but I haven't implemented that yet
    socket.on('queueup', function(data) {
        //if there are already users playing...
        if(pairs.length > 0) {
            //get the index of the last pair...
            var pairIndex = pairs.length-1;
            if(pairs[pairIndex].length < 2) {
                //if pair is not full (means that other user is queued and waiting for opponent), add the user to the pair and start the game//
                pairs[pairIndex].push({
                    'ID' : data,
                    'x' : 850,
                    'y' : 850,
                    'mx' : 0,
                    'my' : 0,
                    'vermove' : 0,
                    'hormove' : 0,
                });
                //add the listener for this user...
                playerMovementListener(socket, pairs[pairIndex][1].ID, pairIndex, 1);
                //update and send coordinates 60 times per second..
                setInterval(function() { runGame(pairs[pairIndex][0], pairs[pairIndex][1], pairIndex); }, 1000/60);
                //send the ready message to the users in the pair..
                io.sockets.emit(pairs[pairIndex][0].ID + ' ready', 'go');
                io.sockets.emit(pairs[pairIndex][1].ID + ' ready', 'go');
            } else {
                //however if pair is already full, create new pair, add user to it, add listener for user and wait for opponent...
                var pair = [];
                pair.push({
                    'ID' : data,
                    'x' : 150,
                    'y' : 150,
                    'mx' : 0,
                    'my' : 0,
                    'vermove' : 0,
                    'hormove' : 0,
                })
                pairs.push(pair);
                playerMovementListener(socket, pairs[pairIndex+1][0].ID, pairIndex+1, 0);
            }
        } else {
            //if no users are playing, add user to first pair, add listener and wait for opponent...
            var pair = [];
            pair.push({
                'ID' : data,
                'x' : 150,
                'y' : 150,
                'mx' : 0,
                'my' : 0,
                'vermove' : 0,
                'hormove' : 0,
            });
            pairs.push(pair);
            playerMovementListener(socket, pairs[0][0].ID, 0, 0);
        }
    });
});

此代码按预期工作。此时,只要玩家断开连接或离开游戏,我只需要删除听众并清除游戏功能的间隔即可。

没有的工作是尝试在第二个玩家连接之后安装两个玩家的监听器(而不是在连接时安装第一个玩家的监听器,即使他们尚未参加游戏) ... 有效)。我什至不知道为什么,但是关键是我可以使用它。