Socket.IO处理断开事件


88

无法处理此断开事件,不知道为什么套接字未发送给客户端/客户端没有响应!

服务器

io.sockets.on('connection', function (socket) {

  socket.on('NewPlayer', function(data1) {

    online = online + 1;
    console.log('Online players : ' + online);
    console.log('New player connected : ' + data1);
    Players[data1] = data1;
    console.log(Players);

  });

  socket.on('DelPlayer', function(data) {

    delete Players[data];
    console.log(Players);
    console.log('Adios' + data);

  });

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

      socket.emit('disconnected');
      online = online - 1;

  });

});

客户

 var socket = io.connect('http://localhost');

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

        person_name = prompt("Welcome. Please enter your name");

        socket.emit('NewPlayer', person_name);

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

            socket.emit('DelPlayer', person_name);

        });

    });

如您所见,当客户端断开连接时,应删除Array对象[person_name],但不删除


您最好尝试其他方法,首先删除播放器,然后断开连接。因为一旦断开与服务器的连接,服务器将无法接收客户端发出的事件。跟踪插槽而不是播放器,可以轻松移除播放器。
code-jaff

如何删除播放器,然后断开连接?我怎么知道播放器何时断开连接?
Raggaer 2013年

4
客户端上的事件不应该'disconnect'代替'disconnected'吗?
Sherlock

1
在OP的原始客户端代码中,@ Sherlock尝试监听自定义事件,这些事件触发服务器端逻辑断开。实际上,“断开连接”是内置的断开连接事件,但它并不直接导致他们遇到的问题。
乔恩·

Answers:


168

好的,不要用名字跟踪玩家,而是通过他们所连接的插座来识别他们。你可以有一个类似的实现

服务器

var allClients = [];
io.sockets.on('connection', function(socket) {
   allClients.push(socket);

   socket.on('disconnect', function() {
      console.log('Got disconnect!');

      var i = allClients.indexOf(socket);
      allClients.splice(i, 1);
   });
});

希望这会帮助您以另一种方式思考


90
最好使用allClients.splice(i, 1)删除元素。delete allClients[i]将数组位置设置为undefined
Yves

1
为什么它起作用了,但是用他们的姓名解决方案跟踪人员却没有起作用?
sha1 2014年

这对我不起作用。这里i拿到了-1每次值。你能告诉我发生了什么吗?
Vinit Chouhan 2015年

1
@VinitChouhan您可能应该在实际问题中提出另一个问题。
code-jaff 2015年

当您获得值-1时,表示您正在尝试拼接一个不存在的套接字(有人断开连接,但尚未在allClients阵列中注册该人)。我建议您返回:if (i === -1)return;在尝试拼接之前。
Koen B.

23

对于@ sha1这样的人,他们想知道OP的代码为什么不起作用-

OP在服务器端删除播放器的逻辑在DelPlayer事件的处理程序中,发出此事件的代码(DelPlayer)在disconnected客户端的内部事件回调中。

发出此disconnected事件的服务器端代码在disconnect事件回调内部,当套接字失去连接时将触发该事件回调。由于套接字已经失去连接,因此disconnected事件不会到达客户端。


接受的解决方案disconnect在服务器端执行事件逻辑,当套接字断开连接时触发该逻辑,因此可以正常工作。


6

创建一个Map或Set,然后使用每个连接的套接字都设置为“ on connection”事件,相反,将“ on一次断开”事件从我们先前创建的Map中删除

import * as Server from 'socket.io';

const io = Server();
io.listen(3000);

const connections = new Set();

io.on('connection', function (s) {

  connections.add(s);

  s.once('disconnect', function () {
    connections.delete(s);
  });

});

1
一位资深人士会提供详细的回答和解释,但我想我们只能用一堆代码来解决
Cemal

让我知道您是否有疑问,我不记得写下答案了
Alexander Mills

1
我实际上没有任何问题。对于作者而言,这只是一种建设性的批评,他更清楚地在评论中使用注释和描述,以使任何人(至少是大多数人)理解您的示例而不会烦扰您。无论如何,新年快乐
。– Cemal

0

如果您喜欢使用套接字ID来管理播放器列表,也可以这样。

io.on('connection', function(socket){
  socket.on('disconnect', function() {
    console.log("disconnect")
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].socket === socket.id){
        console.log(onlineplayers[i].code + " just disconnected")
        onlineplayers.splice(i, 1)
      }
    }
    io.emit('players', onlineplayers)
  })

  socket.on('lobby_join', function(player) {
    if(player.available === false) return
    var exists = false
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].code === player.code){
        exists = true
      }
    }
    if(exists === false){
      onlineplayers.push({
        code: player.code,
        socket:socket.id
      })
    }
    io.emit('players', onlineplayers)
  })

  socket.on('lobby_leave', function(player) {
    var exists = false
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].code === player.code){
        onlineplayers.splice(i, 1)
      }
    }
    io.emit('players', onlineplayers)
  })
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.