Node.js SocketIO识别断开连接的用户

Node.js SocketIO识别断开连接的用户,node.js,express,socket.io,serverside-javascript,Node.js,Express,Socket.io,Serverside Javascript,我正在制作一个简单的Node.js游戏,它使用Express、Socket.io和Http服务器。所有用户都存储在服务器上的多维对象中。以下是服务器端代码的工作方式: var express = require('express'); var app = express(); var http = require('http').Server(app); var io = require('socket.io')(http); app.use(express.static(__dirname +

我正在制作一个简单的Node.js游戏,它使用Express、Socket.io和Http服务器。所有用户都存储在服务器上的多维对象中。以下是服务器端代码的工作方式:

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use(express.static(__dirname + '/'));

var playerList = {};

createPlayer = function(array,width,height,spdx,spdy,x,y,color,name,id) {
  var player = {
    width:width,
    height:height,
    spdx:spdx,
    spdy:spdy,
    x:x,
    y:y,
    wKeyDown:false,
    aKeyDown:false,
    sKeyDown:false,
    dKeyDown:false,
    color:color,
    name:name,
    id:id
  }
  array[id] = player;
}

io.on('connection', function(socket) {
  socket.on('new player', function(id, name) {
    id = parseInt(id);
    if (!playerList[id]) {
      createPlayer(playerList,25,25,4,4,Math.round(Math.random() * 800),Math.round(Math.random() * 600),randomColor(),name,id);
    }

    socket.on('pressW', function(id, keyDown) {
      playerList[id].wKeyDown = keyDown;
    });
    socket.on('pressA', function(id, keyDown) {
      playerList[id].aKeyDown = keyDown;
    });
    socket.on('pressS', function(id, keyDown) {
      playerList[id].sKeyDown = keyDown;
    });
    socket.on('pressD', function(id, keyDown) {
      playerList[id].dKeyDown = keyDown;
    });
  });

  socket.on('disconnect', function() {

  });
};

sendPlayerList = function() {
  //newPlayerList is used to prevent client from seeing other users IDs
  var newPlayerList = {};
  var count = 0;
  for (var q in playerList) {
    player = {
      x:playerList[q].x,
      y:playerList[q].y,
      width:playerList[q].width,
      height:playerList[q].height,
      color:playerList[q].color,
      name:playerList[q].name,
    }
    newPlayerList[count] = player;
    count++;
  }

  io.emit('edit playerlist', newPlayerList);
}

SPLInterval = setInterval(sendPlayerList, 1000);
以下是用于连接的客户端代码:

var id;
$('#playbutton').click(function() {
  var name = document.getElementById('name').value;
  id = Math.floor(Date.now() * Math.random());
  socket.emit('new player', id, name);
});
在客户端,在更新循环中,当游戏想要告诉服务器您的输入时,它会像这样发出您的输入:

update = function() {
    ctx.clearRect(0,0,canvas.width,canvas.height);
    if (document.hasFocus()) {
      socket.emit('pressD', id, dKeyDown);
      socket.emit('pressS', id, sKeyDown);
      socket.emit('pressA', id, aKeyDown);
      socket.emit('pressW', id, wKeyDown);
    }else{
      socket.emit('pressD', id, false);
      socket.emit('pressS', id, false);
      socket.emit('pressA', id, false);
      socket.emit('pressW', id, false);
    }
    clientUpdatePlayer();
    updatePlayers();
  }
}

var updateInterval = setInterval(update, 31.25);
更新玩家的功能只是根据服务器发送的玩家列表绘制玩家

我的问题是,当用户断开连接时,他们会留在玩家列表中。 我不明白我该如何着手解决这个问题。我通过获取用户从客户端发送的ID来识别用户,但是当他们断开连接时,我无法获取用户的ID


还有很多代码,但我试着只包含我认为必要的代码。如果需要,我愿意包含更多的代码。

您可以将
id
值存储在父作用域中,
disconnect
事件处理程序可以访问:

io.on('connection', function(socket) {
  var userId;
  socket.on('new player', function(id, name) {
    userId = id = parseInt(id);
    // ...
  });

  socket.on('disconnect', function() {
    delete playerList[userId];
  });
};

也许我参加聚会迟到了,但我也遇到了类似的事情,我觉得这很难,这可能会对某些人有所帮助

检测用户是否断开连接的最佳方法是首先在套接字会话中设置用户名

在发出时从客户端发送名称

socket.emit("newUser", username);
和在服务器上

socket.on('newUser',function (username) {
     // we store the username in the socket session for this client
     socket.username = username;
});
当用户断开连接时,请在断开连接事件中找到

socket.on('disconnect', function () {
    var connectionMessage = socket.username + " Disconnected from Socket " + socket.id;
    console.log(connectionMessage);
  });

您可以从这里开始。

我们可以使用socket id在playerList中作为参考来存储数据。只要用户断开连接,就可以根据套接字id从对象中删除元素

var playerList = {};
io.on("connection", socket => {

if (!Object.values(playerList).includes(playername) && playername != null) {
      var U_data = {
        [socket.id]: playername
      };
      playerList = { ...playerList, ...U_data };
    }
  socket.on("disconnect", function(e, id) {
    console.log(socket.id);
    delete playerList[socket.id];
    io.emit("broadcast", Object.values(playerList));

  });
}
这对我很有用:

在每个新连接或联机用户上生成套接字Id,将其添加到用户对象,并将其添加到所有联机用户的数组中

const users = [];
io.on('connection', (socket) => {
const socketId = socket.id; 


socket.on('user online', (data) => {

    users.push({ ...data, socketId });
    io.emit('view user online', user);
  });
然后在
断开连接中,使用
forEach
循环遍历数组中的每个对象,然后使用
for
循环遍历和
删除对象中的每个键:

 socket.on('disconnect', () => {
    users.forEach((user) => {
      if (user.socketId === socket.id) {
        for (const key in user) {
          delete user[key];
        }
      }
        });

        logger(`A user has disconnected`);
      });
      });
});

调整到您想要的方式。

这对多个用户有效吗?这不只是将userId变量更改为最近连接的玩家吗?是的,它适用于多个用户。您已经从
连接
事件处理程序中获得了正确的作用域,因此它是相同的套接字,因此是相同的用户。所以,除非你能让一个用户在同一个套接字上同时注册多个玩家名,否则你应该没问题。为什么这是正确的答案?id=1的用户a连接到服务器,用户id现在是1,在id=2的用户B连接到服务器之后,用户a和用户id是2!现在,如果userA断开连接,此回调将从playerList中删除userB!!我认为userId将具有最近加入的用户的id。可能重复:您可以使用上面链接中的事件向服务器发送带有播放机id的断开连接事件,并且可以在收到该事件时将其从列表中删除。请提供更多信息以了解更多详细信息。使用查找已断开连接的用户“socket.id”const presentUser=users.find(user=>user.id==socket.id);然后使用,users=users.filter(user=>user!=presentUser)从在线用户列表中删除此用户;希望您对javascript中的“arrow函数”以及“find”和“filter”数组方法没有问题。
const presentUser=users.find(user=>user.id==socket.id);
此处socket.id指触发断开连接事件的套接字或客户端,或已断开连接的客户端。
var users = [];
socket.on('newUser', (username) => {
    users.push({
        id: socket.id,
        username: username
    });
});
socket.on('disconnect', () => {
     const presentUser = users.find(user => user.id == socket.id);
     users = users.filter(user => user != presentUser);
});