【问题标题】:Socket.IO display connected users list of a roomSocket.IO 显示房间的已连接用户列表
【发布时间】:2020-08-18 01:57:39
【问题描述】:

我有一个 vue.js/node/socket.io 聊天应用程序。我需要创建一个在线用户列表,当用户连接或断开连接时将保持最新状态。我正在尝试使用此代码,但当有人加入房间时,我无法更新用户列表。我该如何解决这个问题?

'use strict';

const express = require('express');
const socketIO = require('socket.io');

const PORT = process.env.PORT || 3000;
const INDEX = '/index.html';

// TODO: controllo query url
const server = express()
.use('/modules', express.static(__dirname + '/node_modules'))
.use('/assets', express.static(__dirname + '/assets'))
.use((req, res) => res.sendFile(INDEX, { root: __dirname }))
.listen(PORT, () => console.log(`Listening on ${PORT}`));
const io = socketIO(server);

let connectedUsers = [];

io.on('connection', (socket) => { 
  console.log('Connected peer: '+ socket.id);
  socket.on('accessRoom', (username,room) => {
    connectedUsers = { nickname: username, id: socket.id } 
    socket.join(room, (err) => {
      socket.emit('accessStatus', 'done');
      console.log(this)
    })
    updateUsersList()
  })

  socket.emit('channelStatus', socketData)
  socket.emit('message', socket.id, 'connected')

  socket.on('message', (id, msg) => { 
    socket.broadcast.emit('message', id, msg);
  })

  socket.on('disconnect', () => {
    console.log('Disconnected')
  })

  function updateUsersList(){
    socket.emit('usersList', connectedUsers)
  }

});

io.on('ping', (socket) => {
  console.log(socket);
  io.emit('pong');
});

vuejs 代码

export default {
  data () {
    return {
      isRegistered: false,
      isConnected: false,
      user: '',
      message: '',
      id: '',
      channel: '',
      usersList: []
    }
  },
  mounted() {
    this.pingServer()
    this.updateUsersList()
    io.on('pong', (data) => {
      console.log(data);
    })
    io.on('channelStatus', (data) => {
        if( data.status === 'connected' ){
          this.id = data.IHMnumber;
          this.isConnected = true;
          console.log(data);
        }
    })
    io.on('message', (from, msg) => {
      console.log(from)
      console.log(msg)
    })
  },
  methods: {
    pingServer(){
      io.emit('ping')
    },
    connect(){
      if( this.isRegistered === false){
        this.user = this.user;
        this.isRegistered = true;
        console.log(this.isRegistered);
        console.log(this.user);
        io.open()
        return this.user;
      }
    },
    updateUsersList(){
      io.on('usersList', (users) => {
        console.log(users);
        this.usersList.push(users);
      })
    },
    sendMessage(){
      console.log(this.message)
      io.emit('message', this.id ,this.message)
    }
  }
}

使用此代码,创建房间的用户将不会收到用户列表。对于将加入房间的用户,在控制台中我可以看到他们已添加到用户数组中,但如果有人加入房间,则事件将不会使用更新的信息登录控制台。也许我需要重构代码,也许我在错误的地方调用了updateUsersList

【问题讨论】:

    标签: node.js vue.js socket.io


    【解决方案1】:

    首先,如果您按房间划分用户,请向他们的房间发送消息https://socket.io/docs/server-api/#socket-to-room。在这里,我向您展示解决问题的一种方法。更改“connectedUsers”的类型,例如,映射,其中键将是房间名称,值 - 用户数组:

    const connectedUsers = new Map();
    

    为了处理用户列表的变化,创建加入方法

    joinToRoom(room, user) {
        // create users array, if key not exists
        if (!connectedUsers.has(room)) {
            connectedUsers.set(room, []);
        }
        // add user to room array
        connectedUsers.get(room).push(user);
        // call update function
        updateUsersList(room);
    }
    

    离开房间:

    leaveRoom(room, user) {
        let userList = connectedUsers.get(room);
        // delete user
        userList = userList.filter(u => u !== user);
        // update user list
        if (!userList.length) {
            // delete key if no more users in room
            connectedUsers.delete(room);
        } else
        {
            connectedUsers.set(room, userList);
            // call update function
            updateUsersList(room);
        }
    }
    

    还可以更改您的方法 updateUsersList:

    function updateUsersList(room){
        socket.to(room).emit('usersList', {
            room: room,
            users: connectedUsers.get(room)
        });
    }
    

    请注意,我们向事件 'usersList' 发出带有房间字段的对象,以便澄清您应该在前端更新哪个房间。

    最后一步是调用我们的方法:

    当用户加入房间时:

    socket.join(room, (err) => {
      const user = resolve user from request;
      socket.emit('accessStatus', 'done');
      joinToRoom(room, user);
      console.log(this);
    })
    

    当用户离开房间时: 我没有看到离开房间的事件,所以你只需调用 leaveRoom(room, user)

    您还应该创建一些映射来比较 socketId 和用户,以正确处理断开连接事件并调用 leaveRoom(room, user) 方法。

    【讨论】:

    • 我需要尝试测试您的代码,我现在正在尝试使用似乎将引用所有套接字连接的io.sockets。这将使我能够发送新的连接更新到在同一个房间内连接的客户端,但我不确定是否也为与加入房间不同的其他房间触发了事件(这不是预期的行为)
    • 对于您建议的 leaveRoom 功能,我是否可以应用任何特定代码来从 users 数组中删除断开连接的客户端?
    • 我认为文档中的示例适合您socket.io/docs/server-api/… 只是想添加,您可以映射房间变量并在 leaveRoom 函数中调用
    • 我正在测试您建议的代码,但在节点中我收到此行错误 const user = resolve user from request; 任何修复?节点服务器将无法运行,我收到 SyntaxError: Unexpected identifier
    • 这是一条评论))在那里你可以实现你的逻辑来解析用户。我不知道您的身份验证策略,所以我无法向您展示具体示例。一定是1) get token from request 2) in case of jwt parse token 3) find user data in db 4) set user data to const user
    猜你喜欢
    • 2021-04-20
    • 2018-01-09
    • 2020-02-24
    • 2020-07-30
    • 1970-01-01
    • 2017-11-29
    • 2020-11-23
    • 1970-01-01
    • 2013-04-06
    相关资源
    最近更新 更多