Socket.IO - how to get different active user lists

2019-02-20 02:49发布

问题:

I am writing a simple socket.io(v1.3.6)-based chatting program. When users log in with their username, they could see several chatting rooms in dashboard and enter each of them via different end ponts, i.e,

http://localhost:8080/api/chats/room01.

Users could chat in any one of these rooms. For each room, I would like to create an active user list. 'active' means this user is now connected to socket (chatting in this room).

I see many questions have been posted but still confused by their few isolated words.

In my current server.js, I added this code:

var io = require('socket.io')(http);

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

  console.log('a user connected: ' + socket.id);

  socket.on('disconnect', function(){
    console.log(socket.id + ' has disconnected from the chat.');
  });

});

To sum up, two questions:

  • How can I distinguish the socket connections for different rooms/endpoints?

  • How can I get active usenames instead of socket.id which could be different for the same user?

Thanks a lot.

Update:

My server-side code:

io.of('/rooms/room01').on('connection', function(socket) {

  console.log("socket connected: ", socket.id);
  //....some more codes

});

My client-side code:

app.factory('socketio', ['$rootScope', function($rootScope) {
  'use strict';

  var socket = io.connect('http://localhost:8080/rooms/room01');
  return {

    on: function(eventName, callback) {
      socket.on(eventName, function() {
        var args = arguments;
        $rootScope.$apply(function() {
          callback.apply(socket, args);
        });
      });
    },

    emit: function(eventName, data, callback) {
      socket.emit(eventName, data, function() {
        var args = arguments;
        $rootScope.$apply(function() {
          if (callback) {
            callback.apply(socket, args);
          }
        });
      });
    }
  };
}]);

The above code does not work. But previously when I use the default namespace

io.of('/').on('connection', function(socket) {
  //...
}

and

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

it works well. Could you pls let me know why?

回答1:

How can I distinguish the socket connections for different rooms/endpoints?

On your server, there are a couple ways to list the various rooms and sockets in each room. Here's some info about the various data you can access on the server and you can then decide which is the most efficient way to get what you want:

io.sockets.adapter.rooms

This is a object containing all the rooms as keys that currently have at least one connection in them. This contains both rooms your server called .join() for to manually join a socket to a room and contains each default room (with the name of the socket.id) that each socket is automatically joined to. So, if you know you have a room by the name of "test", then you can get an object with each room as keys with io.sockets.adapter.rooms['test'].

io.sockets.connected

This is an object containing each socket that is currently connected where the socket.id is the key in the object. So, if the id is vlPYz3EHUOe8vFitAAAJ, then you can access the socket object for that id as io.sockets.connected['vlPYz3EHUOe8vFitAAAJ']. You can obviously iterate all connected sockets by using a for (var sock in io.sockets.connected) type of loop. Then, inside that socket object, you can see which rooms it is in via: io.sockets.connected['vlPYz3EHUOe8vFitAAAJ'].rooms which is an array of room names it is in. This array of room names will include the automatic room of the same name as the socket.id.

io.sockets.sockets

This is an array of connected sockets and is perhaps an easier way to access all the currently connected sockets than using io.sockets.connected. Like described in the previous section once you have a given connected socket, you can access the socket.rooms property to get an array of rooms that socket is currently in.

For a specific socket, you can get a list of rooms that it is in via:

socket.rooms

which is an array of the room names that a given socket is currently in. This includes the automatic room name of the same name as the socket.id so you may want to ignore that room name if just trying to list the regular rooms that a socket is in.

How can I get active usenames instead of socket.id which could be different for the same user?

Since usernames are something you assigned and have nothing to do with socket.io in particularly, you will have to find a way to associate the username with the socket yourself. Depending upon where the username is known, you can do that in different places. If it is already present in a cookie, then you can fetch it from: socket.handshake.headers.cookie which is a snapshot of the cookies that were set for this particular socket at the time the socket was initially connected.

If the username is known some other way at the time that the socket is initially connected, you can grab it from that other mechanism and save it as a property of the socket object: socket.username = 'xxx'; and then you can access it from the server-side socket object at any time.

Here's some server-side diagnostic code that I've used to explore these various data structures:

'use strict';
var express = require('express');
var app = express();
var server = app.listen(80);
var io = require('socket.io')(server);
app.use(express.static('public'));

io.on('connection', function(socket) {
    console.log("socket connected: ", socket.id);

    // list all connected sockets
    var list = io.sockets.sockets;
    console.log("Connected sockets:");
    list.forEach(function(s) {
        console.log("    socket.id = ", s.id);
    });

    socket.on('join', function(name) {
        socket.join(name);

        // list all rooms
        console.log("Active rooms:");
        var rooms = io.sockets.adapter.rooms;
        for (var room in rooms) {
            if (rooms.hasOwnProperty(room)) {
                console.log("     ", room);
            }
        }

        // list all rooms this socket is in:
        console.log("Active rooms for this socket:");
        io.sockets.connected[socket.id].rooms.forEach(function(room) {
            console.log("    ", room);
        });


    });

    socket.on('leave', function(name) {
        socket.leave(name);
    });

});