Socket.io: 为什么客户端的 socket.disconnect() 不会在服务器上触发断开事件?

创建于 2015-11-04  ·  23评论  ·  资料来源: socketio/socket.io

这是我的代码:

客户端

 var socket = io.connect('http://' + serverAddress ,{ reconnection: false, forceNew: true  }  );

 socket.emit('monitorAddedNotify' , { video: sourceVideo , socketId: socket.id});

 socket.on('disconnectThatSoc', function(){
    socket.disconnect();
});

服务器端:

  io.on('connection', function (socket) {
    console.log('a user connected');


    socket.on('disconnect', function () {
        console.log('user disconnected');
    });
 });

socket.disconnect() 方法不起作用,为什么?

Unable to reproduce

最有用的评论

你傻吗? 您正在等待客户端上的发射,但服务器上没有发射。 他妈的离开这里

所有23条评论

据我测试,它工作正常。 我们如何重现这个问题?

尝试按多次 F5 按钮进入页面并快速重新加载。

它对我也很好。

您使用哪种浏览器? 我正在使用最新的 Firefox,当我快速重新加载时,“用户已断开连接”不起作用:失望:

我也有问题。 在这些动作中,断开连接,但它来得比重新启动浏览器要晚得多。

浏览器:Chrome 55.0.2883.95(64 位)
socket.io:“^1.7.2”

嗨@ventaquil。 按住 F5 时断开连接事件没有触发,我遇到了同样的麻烦。 你克服了这个吗?

@giathinh910不是在给定延迟后触发的disconnect事件(可能与pingTimeout / pingInterval选项有关,在此处记录)?

@darrachequesne我的问题与上面描述的@ventaquil “尝试进入页面并通过多次按F5按钮快速重新加载”相同。 通常,当您刷新页面套接字连接时,会触发“断开”然后再次“连接”。 我依靠这两个事件来更新在线用户的数量。 但是,如果页面重新加载速度足够快,“断开连接”将不会触发,这会导致添加一些不存在的用户套接字 ID。 这些虚幻的人当然会在 pingTimeout 之后被移除。 目前我改变了保存socket id的方式,只显示在线用户,而不是socket的数量,问题可以解决。

我就是这样处理这个问题的。 我在客户端发出了一个发送者,它在服务器上调用心跳。
socket.on("heartbeat", function() { // console.log('heartbeat called!'); hbeat[socket.id] = Date.now(); setTimeout(function() { var now = Date.now(); if (now - hbeat[socket.id] > 5000) { console.log('this socket id will be closed ' + socket.id); if (addedUser) { --onlineUsers; removeFromLobby(socket.id); try { // this is the most important part io.sockets.connected[socket.id].disconnect(); } catch (error) { console.log(error) } } } now = null; }, 6000); });

我发现这个代码函数可以调用:

io.sockets.connected[socket.id].disconnect();

这仍然会发生。 它不必是 F5/刷新。 在某个阶段打开一个选项卡并很快将其关闭,导致不会触发断开连接。 很难重现,因为套接字非常快,尤其是在本地运行时。 我注意到在后台打开选项卡并打开其他选项卡有助于(本地)重现问题。 我认为这是一个应该解决的重要错误。

这里有同样的问题。 这是在我的游戏服务器上创建幽灵游戏

也许要手动断开客户端,您可以使用带有一些发射的功能。
我不知道这是否会有所帮助,但我想我得到了一些东西......也许......

客户

function ManualSocketDisconnect() {
    socket.emit("manual-disconnection", socket.id);

    socket.close();

    console.log("Socket Closed. ");
}

服务器

io.on("connection", function(socket) {
    console.log("User " + socket.id + " Connected. ");

    socket.on("manual-disconnection", function(data) {
        console.log("User Manually Disconnected. \n\tTheir ID: " + data);
    });
});

对不起,但我可能在我的代码中留下了一些漏洞。 我不是专业人士。 🙁

我面临同样的问题!
我将在 ReactJS-ExpressJS 中给出示例。

这是将触发事件的情况,并封装在componentWillUnmount()中。

我将比较两个事件,我将从componentWillUnmount()触发

  1. newMessage :- 这会将消息广播到特定房间
  2. disconnect :-(我希望它会工作,但它没有) 这个事件监听器有回调,它将断开连接。 我包含一个console.log()只是为了确认回调是否命中。

现在,我们开始:-
客户:-

这些事件正在被触发:-

  componentDidMount() {
    console.log(this.props)
    chat.emit('authenticate', {
      token: localStorage.getItem('auth'),
      refreshToken: localStorage.getItem('refresh'),
      projectId: this.props.projectId,
      userId: this.props.userId,
    });
    chat.on('newMessage', (messageData) => {
      console.log('------------newMessageReceived-------------');
      this.props.messageReceived({ messages: this.props.messages, messageData }, () => {
        console.log('callback');
        this.setState({
          messages: this.props.messages
        })
      })
      console.log(messageData);
    })
  }

以下事件不会触发。

  componentWillUnmount() {
    chat.emit('disconnect','just disconnect);
  }

将触发以下事件。(仅测试是否发出正常消息事件)

  componentWillUnmount() {
    chat.emit('newMEssage', {
      messageHeader: {
        sender: {
          user: {
            id: this.props.userId,
            name: this.props.name
          }
        }
      },
      messageBody: 'hello',
    });
  }

没有运气

服务器:-
这是 expressJS 后端的代码

//下面的initializeChatSocket在app.js中被调用

function initializeChatSocket(server) {
  projects.hasMany(projectTeam, { foreignKey: 'projectId' });

  const io = socketIO(server);
  const chat = io.of('/chat').on('connection', function (socket) {
    console.log(
      '----------------------------------------New Chat Connection Established-------------------------------------------------------------------------'
    );

    socket.auth = false;

    socket.on('authenticate', function (data) {
      console.log('\n\n\n\n', 'authenticate called', '\n\n\n\n', data, '\n\n\n');

      try {
        const dummyReq = {
          headers: {
            refreshtoken: data.refreshToken,
          },
        };
        console.log('\n\n\n\n', 'before verify', '\n\n\n\n');
        const userDetails = verifyJWTToken(dummyReq, data.token);
        console.log('\n\n\n\n', 'after verify', '\n\n\n\n');
        socket.userId = userDetails.userId;
        socket.projectId = data.projectId;

        projectTeam
          .findAll({
            where: {
              [Op.and]: {
                projectId: data.projectId,
                userId: data.userId,
              }
            }
          })
          .then(projects => {
            console.log('\n\n\n\n', JSON.stringify(projects), '\n\n\n\n');
            if (projects.length === 1) {
              socket.auth = true;
              socket.join(socket.projectId);
              console.log('User id:- ${userDetails.userId} linked to project id :- ${socket.projectId}');
            } else {
              console.log('User id:- ${userDetails.userId} not linked to project id :- ${socket.projectId}');
              throw { message: 'User not linked to project' };
            }
          });
      } catch (error) {
        console.log(String(error));

        socket.auth = false;
        socket.disconnect(String(error));
      }
    });

    socket.on('disconnectt', function() {
      console.log('Client Disconnecting'); // This is not being fired :/
      socket.removeAllListeners('newMessage');
      socket.removeAllListeners('disconnect');
      socket.removeAllListeners('authenticate');
      socket.removeAllListeners('connection');
      });

    socket.on('newMessage', async function (messageData) {
      console.log('-------------------------New Message----------------------', String(messageData));
      //TODO Save Message in Database

      try {
        socket.broadcast.to(socket.projectId).emit('newMessage', messageData);
        console.log('\n\n\n\n\n broadcast sent\n\n' + JSON.stringify(messageData) + '\n\n\n');
      } catch (error) {
        console.log('\n\n\n\n\n broadcast error\n\n\n\n\n');
        console.log(String(error));

        console.log(error);
        //TODO Handle Message Sending Error
      }
    });

  });
}

这是浏览器的任何问题还是我需要从堆栈溢出社区询问的其他问题?

@manjotsk我不确定您现在是否已修复它,但是在您的服务器端代码上,您正在侦听disconnectt (注意双t )但您的前端正在发射disconnect 。 此外,您可能不想发出disconnect因为该事件应该在客户端断开连接时从客户端发送到服务器。

我的代码依赖于发出断开连接事件的套接字来防止重复的 ips——重新加载我的应用程序的用户很快就会被阻止,因为断开连接甚至永远不会触发!

@manjotsk我不确定您现在是否已修复它,但是在您的服务器端代码上,您正在侦听disconnectt (注意双t )但您的前端正在发射disconnect 。 此外,您可能不想发出disconnect因为该事件应该在客户端断开连接时从客户端发送到服务器。
disconnectt是我使用的冒名顶替者别名! 谢谢你指出。 我会在两边重新检查。 而且,显然,实施是错误的! 我看得更清楚了! 谢谢@nathanheffley 👍 :)

@manjotsk什么?

并且只使用 socket.once 而不是 socket.on
“客户级别。”
例子:
socket.on('连接')
采用
socket.once('连接'
.

我的也一样
socket.on("message") { (dataArray, socketAck) -> Void in

  if let data = dataArray.first as? Data{
    do{
      let objc = try JSONDecoder.init().decode(GetChatConversation.self, from: data)
      completionHandler(objc,nil)
    }
    catch let error{
      return completionHandler(nil,error.localizedDescription)
    }
  }else{
    completionHandler(nil,"Cannot cast Array of Any to Data")
  }
}

如果有人知道告诉我,请不要返回回调

你傻吗? 您正在等待客户端上的发射,但服务器上没有发射。 他妈的离开这里

这是一些真正的负能量,Ehsan666x。

我就是这样处理这个问题的。 我在客户端发出了一个发送者,它在服务器上调用心跳。
hbeat[socket.id] = Date.now();

我想知道应该从客户端发送什么hbeat值?

而不是socket.disconnect()socket.emit('disconnect') socket.close(); ,它应该在服务器端触发'disconnect'事件。 它对我有用。

此页面是否有帮助?
0 / 5 - 0 等级