Socket.IO: ¿cómo obtengo una lista de sockets / clientes conectados?

159

Estoy tratando de obtener una lista de todos los sockets / clientes que están conectados actualmente.

io.sockets no devuelve una matriz, desafortunadamente.

Sé que podría mantener mi propia lista usando una matriz, pero no creo que esta sea una solución óptima por 2 razones:

  1. Redundancia. Socket.IO ya guarda una copia de esta lista.

  2. Socket.IO proporciona un método para establecer valores de campo arbitrarios para los clientes (es decir:), socket.set('nickname', 'superman')por lo que necesitaría mantenerme al día con estos cambios si tuviera que mantener mi propia lista.

¿Ayuda?

Andy Hin
fuente
¿No puedes convertir io.sockets en una matriz?
marzo
2
En 0.7.6 io.sockets.sockets es un simple objeto hash id => socket
mak
1
Me di cuenta de eso, pero está actuando de forma extraña (no parece un objeto de socket estándar). Por ejemplo, intenté: pastebin.com/fxuzVckS pero dice que el objeto de socket no contiene un método 'get'.
Andy Hin
3
socketes id, io.sockets.sockets[socket]es el zócalo.
mak
2
El primer argumento es erry si está utilizando el almacén de memoria es siempre null. .get('nickname', function(err, nickname) { ... })
mak

Respuestas:

173

En Socket.IO 0.7 tiene un clientsmétodo en los espacios de nombres, esto devuelve una matriz de todos los sockets conectados.

API para ningún espacio de nombres:

var clients = io.sockets.clients();
var clients = io.sockets.clients('room'); // all users from room `room`

Para un espacio de nombres

var clients = io.of('/chat').clients();
var clients = io.of('/chat').clients('room'); // all users from room `room`

Espera que esto ayude a alguien en el futuro

NOTA: Esta solución SOLO funciona con la versión anterior a la 1.0


ACTUALIZADO 2020 Mar 06

Desde 1.xy superior, consulte este enlace: obtener cuántas personas hay en una sala de chat en socket.io

3rdEden
fuente
3
Creo que han caído el método de clientes en 1,0 ... sólo la comprobación de que por el momento ...
marksyzm
77
Dejaron casi todo en 1.0 ya que es una reescritura completa. Pero como 1.0 ha sido inédito durante años. En 1.0 tienes que usar el connectedobjeto del espacio de nombres.
3rdEden
66
@ 3rdEden, ¿cuál es la sintaxis para usar el objeto conectado del espacio de nombres? var clients = io.sockets.connected();Obviamente no funciona. Gracias
Kaya Toast
55
De 1.xy superior: stackoverflow.com/questions/9352549/…
Musa Haidari
TypeError: fn.bind no es una función
Iman Marashi
101

Socket.io 1.4

Object.keys(io.sockets.sockets); te da todos los enchufes conectados.

Socket.io 1.0 A partir de socket.io 1.0, la respuesta real aceptada ya no es válida. Entonces hice una pequeña función que uso como una solución temporal:

function findClientsSocket(roomId, namespace) {
    var res = []
    // the default namespace is "/"
    , ns = io.of(namespace ||"/");

    if (ns) {
        for (var id in ns.connected) {
            if(roomId) {
                var index = ns.connected[id].rooms.indexOf(roomId);
                if(index !== -1) {
                    res.push(ns.connected[id]);
                }
            } else {
                res.push(ns.connected[id]);
            }
        }
    }
    return res;
}

Api para Sin espacio de nombres se convierte

// var clients = io.sockets.clients();
// becomes : 
var clients = findClientsSocket();

// var clients = io.sockets.clients('room');
// all users from room `room`
// becomes
var clients = findClientsSocket('room');

La API para un espacio de nombres se convierte en:

// var clients = io.of('/chat').clients();
// becomes
var clients = findClientsSocket(null, '/chat');

// var clients = io.of('/chat').clients('room');
// all users from room `room`
// becomes
var clients = findClientsSocket('room', '/chat');

También vea esta pregunta relacionada , en la que le doy una función que devuelve los sockets para una habitación determinada.

function findClientsSocketByRoomId(roomId) {
var res = []
, room = io.sockets.adapter.rooms[roomId];
if (room) {
    for (var id in room) {
    res.push(io.sockets.adapter.nsp.connected[id]);
    }
}
return res;
}

Socket.io 0.7

API para ningún espacio de nombres :

var clients = io.sockets.clients();
var clients = io.sockets.clients('room'); // all users from room `room`

por un espacio de nombres

var clients = io.of('/chat').clients();
var clients = io.of('/chat').clients('room'); // all users from room `room`

Nota: Dado que parece que la API socket.io es propensa a romperse, y algunas soluciones dependen de los detalles de implementación, podría ser una cuestión de rastrear a los clientes usted mismo:

var clients = [];

io.sockets.on('connect', function(client) {
    clients.push(client); 

    client.on('disconnect', function() {
        clients.splice(clients.indexOf(client), 1);
    });
});
nha
fuente
3
Gracias por esto. Me sorprende que hayan sacado esta funcionalidad.
Tyler Scott
1
@TylerScott Me también, especialmente dado que esto no está cubierto en su guía de migración (a menos que me falte algo). socket.io/docs/migrating-from-0-9
nha
@nha, esto no funciona para mí, pero devuelve una matriz de enteros, como 0, 1 y 2, etc. en lugar de una matriz de sockets. ¿Algunas ideas?
ThePixelPony
¿qué tal para múltiples nodos? porque uso múltiples nodos con redis store
John Nguyen
3
@nha su respuesta es exactamente, pero no funciona para múltiples nodos con el servidor de redis store. desde el proceso de 1 nodo, no puede verificar el socket conectado o no usando ns.connected [id]
John Nguyen
46

Después de socket.io 1.0 no podemos usar

io.sockets.clients(); 
or
io.sockets.clients('room'); 

nunca más. En su lugar, puede usar lo siguiente

var clients_in_the_room = io.sockets.adapter.rooms[roomId]; 
for (var clientId in clients_in_the_room ) {
  console.log('client: %s', clientId); //Seeing is believing 
  var client_socket = io.sockets.connected[clientId];//Do whatever you want with this
}
salihcenap
fuente
3
me cambio avar clients_in_the_room = io.sockets.adapter.rooms[roomId].sockets
Fábio Zangirolami
37

Usando Socket.IO 1.x:

Obtenga una variedad de clientes conectados:

io.engine === io.eio // => true
Object.keys(io.engine.clients) // => [ 'US8AxrUrrDF_G7ZUAAAA', 'Ov2Ca24Olkhf2NHbAAAB' ]
Object.keys(io.eio.clients)    // => [ 'US8AxrUrrDF_G7ZUAAAA', 'Ov2Ca24Olkhf2NHbAAAB' ]

Obtenga el número de clientes conectados:

io.engine.clientsCount // => 2
io.eio.clientsCount    // => 2
Joseph Dykstra
fuente
32

Muy simple en socket.io 1.3:

io.sockets.sockets- es una matriz que contiene los objetos de socket conectados. Si almacenó el nombre de usuario en cada socket, puede hacer:

io.sockets.sockets.map(function(e) {
    return e.username;
})

Auge. Tienes los nombres de todos los usuarios conectados.

o29544
fuente
2
¡Gracias! +1 por simplicidad. ¿Sabes si hay alguna diferencia entre este método y, por ejemplo, la respuesta de Joseph Dykstra? (Object.keys(io.engine.clients)
cyclingLinguist
44
Esto no funciona en v1.4.5. Todavía estoy trabajando en una solución
Nuno Furtado
¿Lo encontraste? \
ocram
2
TypeError: io.sockets.sockets.map no es una función
Király István
23

He pasado por este dolor hoy. Socket.io sería mucho mejor si pudieran hacer una documentación adecuada para su API.

De todos modos, traté de buscar en io.sockets y encontré varias opciones que podemos usar:

io.sockets.connected //Return {socket_1_id: {}, socket_2_id: {}} . This is the most convenient one, since you can just refer to io.sockets.connected[id] then do common things like emit()
io.sockets.sockets //Returns [{socket_1}, {socket_2}, ....]. Can refer to socket_i.id to distinguish
io.sockets.adapter.sids //Return {socket_1_id: {}, socket_2_id: {}} . Looks similar to the first one but the object is not actually the socket, just the information.

// Not directly helps but still relevant
io.sockets.adapter.rooms //Returns {room_1_id: {}, room_2_id: {}}
io.sockets.server.eio.clients //Return client sockets
io.sockets.server.eio.clientsCount //Return number of connected clients

Además, tenga en cuenta que cuando use socket.io con el espacio de nombres, los métodos anteriores se romperán ya que io.sockets se convierte en una matriz en lugar de un objeto. Para resolverlo, simplemente reemplace io.sockets por io (es decir, io.sockets.connected se convierte en io.connected, io.sockets.adapter.rooms se convierte en io.adapter.rooms ...)

Probado en socket.io 1.3.5

Thanh Nguyen
fuente
1
@ Зелёный Funcionará si no está utilizando el espacio de nombres. Si está utilizando el espacio de nombres, cambie a io.server.eio.clientsCount
Thanh Nguyen
2
Sí, la documentación oficial podría mejorarse mucho
CodeAndCats
18

Versión +2.0

En la versión +2.0, especifica el espacio de nombres / sala / nodo contra el que está consultando.

Al igual que con la transmisión, el valor predeterminado es todos los clientes del espacio de nombres predeterminado ('/'):

const io = require('socket.io')();  
io.clients((error, clients) => {
      if (error) throw error;
      console.log(clients); // => [6em3d4TJP8Et9EMNAAAA, G5p55dHhGgUnLUctAAAB]
});

Obtiene una lista de ID de clientes conectados a un espacio de nombres específico (en todos los nodos, si corresponde).

const io = require('socket.io')();
io.of('/chat').clients((error, clients) => {
     if (error) throw error;
     console.log(clients); // => [PZDoMHjiu8PYfRiKAAAF, Anw2LatarvGVVXEIAAAD]
});

Un ejemplo para obtener todos los clientes en la sala del espacio de nombres:

const io = require('socket.io')();
io.of('/chat').in('general').clients((error, clients) => {
      if (error) throw error;
      console.log(clients); // => [Anw2LatarvGVVXEIAAAD] 
});

Esto es de la documentación oficial: Socket.IO Server-API

John Galt
fuente
1
¿Hay alguna manera de ver todos los objetos de socket ? por ejemplo, si agrego una socket.usernamepropiedad a cada socket en la conexión, ¿hay alguna manera de ver todos estos objetos de socket (incluidas las propiedades personalizadas que agrego a cada socket)? (como referencia, actualmente estoy usando una variable de objeto global para almacenar información de socket adicional cuando un cliente se conecta, por lo que no estoy preguntando cómo configurarlo, solo estoy interesado en saber si hay una manera de ver todos los objetos de socket de forma predeterminada) .
user1063287
1
hmm, por esta respuesta , creo que se puede ver todos los enchufes conectados con console.log(io.sockets.connected)- parece ser un objeto que cada valor de la propiedad es un "objeto socket", que contiene estas propiedades nsp, server, adaptor, id(una cadena), client, conn, rooms, acks, connected, disconnected, handshake, fns, flags, _rooms, _events, _eventsCounty, finalmente, usernameque es la propiedad personalizada agrego a cada zócalo de conexión.
user1063287
17

Creo que podemos acceder al objeto de socket desde el servidor, y puede asignar el apodo y señalar su id de socket,

io.sockets.on('connection',function(socket){ 
    io.sockets.sockets['nickname'] = socket.id;
    client.on("chat", function(data) {      
        var sock_id = io.sockets.sockets['nickname']
        io.sockets.sockets[sock_id].emit("private", "message");
    });    
});

En disconnectpor favor elimine el apodo de io.sockets.sockets.

sunil n jose
fuente
¿Cuál es el propósito de 'client.on'? ¿Puede usar su código de esta manera (solo acepta datos de 1 socket) ?: io.sockets.sockets [sock_id] .on ('newmessage', function (data) {console.log (data)});
The Hawk
9

Esta es la mejor manera de acceder a ella en socket.io 1.3

Object.keys(socket.adapter.rooms[room_id])

ksloan
fuente
permítanme compartir este ejemplo: var room = io.sockets.adapter.rooms[room_id]; var connections = _.map(Object.keys(room), function(socketId){ return (io.sockets.connected[socketId].connected == true) });
Hany Alsamman
5

Para cualquiera que solo quiera un CONTEO de los clientes conectados, creo que esto lo hará:

io.sockets.manager.server.connections

crickeys
fuente
No es el recuento de clientes conectados, probado. (poco más)
mrzmyr
55
para obtener un recuento exacto usoio.sockets.clients().length
Ivo
2
Actualmente ambos io.sockets.manager.server.connectionsy io.sockets.clients().lengthno funcionan. Esto funcionó para mí, solo para contar, io.engine.clientsCounty para la lista de clientes io.engine.clientsCount. Como se ha mantenido así durante más de 3 años. Parece una forma confiable de obtener la información de conexión. (Basado en la respuesta de Joseph Dykstra)
Aswin Ramakrishnan
5

Socket.io 1.4.4

Código de muestra para ti.

function get_clients_by_room(roomId, namespace) {
        io.of(namespace || "/").in(roomId).clients(function (error, clients) {
            if (error) { throw error; }
            console.log(clients[0]); // => [Anw2LatarvGVVXEIAAAD]
            console.log(io.sockets.sockets[clients[0]]); //socket detail
            return clients;
        });
    }

Creo que ayudará a alguien a bloquear este código.

Tiago Zamperini
fuente
4

En Socket.IO 1.4

Para obtener la matriz de Todos los usuarios conectados:

var allConnectedClients = Object.keys(io.sockets.connected);// This will return the array of SockeId of all the connected clients

Para obtener el recuento de todos los clientes:

var clientsCount = io.engine.clientsCount ; // This will return the count of connected clients
KIA
fuente
Confirmo que esto funciona en la versión 1.5.1 de socket.io
Sébastien
3

A partir de socket.io 1.5, observe el cambio de indexOf que parece depreciarse y reemplazarse por valueOf

function findClientsSocket(roomId, namespace) {
    var res = [];
    var ns = io.of(namespace ||"/");    // the default namespace is "/"

    if (ns) {
        for (var id in ns.connected) {
            if (roomId) {
                //var index = ns.connected[id].rooms.indexOf(roomId) ;
                var index = ns.connected[id].rooms.valueOf(roomId) ; //Problem was here

                if(index !== -1) {
                    res.push(ns.connected[id]);
                }
            } else {
                res.push(ns.connected[id]);
            }
        }
    }
    return res.length;
}

Para socket.io versión 2.0.3, funciona el siguiente código:

function findClientsSocket(io, roomId, namespace) {
    var res = [],
        ns = io.of(namespace ||"/");    // the default namespace is "/"

    if (ns) {
        for (var id in ns.connected) {
            if(roomId) {
                // ns.connected[id].rooms is an object!
                var rooms = Object.values(ns.connected[id].rooms);  
                var index = rooms.indexOf(roomId);
                if(index !== -1) {
                    res.push(ns.connected[id]);
                }
            }
            else {
                res.push(ns.connected[id]);
            }
        }
    }
    return res;
}
MoleIsKing
fuente
no te imaginas cuánto dolor me has salvado
nicholaswmin
¡pero la versión socket.io aún no es 1.5! Ahora es 1.4.8
leszek.hanusz
@MoleIsKing Obrigado amigo!
2

en socket.io 1.3 he logrado esto en 2 líneas

var usersSocketIds = Object.keys(chat.adapter.rooms['room name']);
var usersAttending = _.map(usersSocketIds, function(socketClientId){ return chat.connected[socketClientId] })
Coelhone
fuente
2

Socket.io 1.7.3 (+):

función getConnectedList ()
{
    let list = []
    
    para (dejar al cliente en io.sockets.connected)
    {
        list.push (cliente)
    }
    
    lista de retorno
}

console.log (getConnectedList ())

// devuelve ['yIfhb2tw7mxgrnF6AAAA', 'qABFaNDSYknCysbgAAAB']

Alexandre Daubricourt
fuente
2

Para la versión 2.3 esto funciona y también le dará el socket , me parece que socketIo está cambiando demasiado rápido y con mucha o poca documentación legible después de usarlo por un tiempo.

ioSite.of('/').in(roomId).clients((error, clients) => {
    if (error) throw error;
    for (var i=0;i<clients.length;i++) {
        clientId=clients[i];
        console.log(clientId);

        // load the socket of your namespace
        var socket=ioSite.of('/').in(roomId).connected[clientId]
        console.log(socket.constructor.name);
        console.log(socket.id);
    }
});

todavía esto no se siente bien, ya que siempre tengo este sentimiento con socket Io de alguna manera

Joris Ceelen
fuente
1
Estoy empezando a pensar que es una biblioteca basura. lo único que hace bien es transferir sin problemas muchos tipos de datos (json, binarios, etc.) de lo contrario, toda la arquitectura es una mierda y no escala más allá de la aplicación de chat 1 a 1
Muhammad Umer
1

¿Creo que puede acceder a esto desde la propiedad del administrador del socket?

var handshaken = io.manager.handshaken;
var connected = io.manager.connected;
var open = io.manager.open;
var closed = io.manager.closed;
Dan Steele
fuente
La respuesta de 3rdEden no funcionó para mí, ya que hay problemas con la matriz que devuelve clientes desconectados, lo que descarta el conteo. Object.keys (io.manager.open) .length resultó ser el recuento más confiable en mi experiencia. io.of ('/ namespace'). manager.open si está utilizando espacios de nombres.
Wes Johnson
1

Veo muchas buenas respuestas aquí y muchas fueron muy útiles, pero no exactamente lo que necesitaba. Estoy usando sockets para una función de pubsub en la que un cliente interesado puede escuchar cualquier cambio en un registro dado.

Mi problema específico era que el mismo conector se unía a la misma habitación varias veces. La solución a esto fue verificar si el zócalo ya tenía la habitación dentro de su propiedad.

var room = myObj.id.toString();
if (socket.rooms.indexOf(room) === -1) {
    socket.join(room);
    socket.emit('subscribed', {to : room});
} else {
    console.log("Already in room");
}

Espero que esto ayude a alguien.

Gus Ortiz
fuente
Creo que es posible evitar esa declaración 'si', si hace que el cliente se una a la sala con la conexión de socket.
Chayemor
¿De dónde viene myObj? ¿Cómo llegaste a ese valor?
Michael Draper
@MikeDraper myObject es el registro en una base de datos que actúa como un canal. Lo que esto resuelve es el caso en el que desea que todos sus clientes se actualicen siempre que ocurra un cambio en la base de datos, por ejemplo, un usuario actualiza su nombre y todos los clientes conectados obtienen una actualización. Así que creo una sala para esa identificación de instancia, dado que es única (BSON). Es un valor muy específico para mi caso de uso, así que lo siento si causé alguna confusión. Avíseme si necesita ayuda :)
Gus Ortiz
@JMR debido a la naturaleza de mi aplicación, sucedió que un socket se suscribió más de una vez, por eso tuve que agregar ese cheque.
Gus Ortiz
1

Esta es la forma más simple en Socket.IO 1.0+, si no está utilizando espacios de nombres o habitaciones.

io.nsps["/"].sockets.length

Esto examina el espacio de nombres predeterminado y determina la longitud de la matriz de sockets, sin necesidad de usar Object.keys()

cañón solar
fuente
1

A partir de la versión 1.5.1, puedo acceder a todos los sockets en un espacio de nombres con:

var socket_ids = Object.keys(io.of('/namespace').sockets);
socket_ids.forEach(function(socket_id) {
    var socket = io.of('/namespace').sockets[socket_id];
    if (socket.connected) {
        // Do something...
    }
});

Por alguna razón, están usando un objeto simple en lugar de una matriz para almacenar las ID de socket.

rppc
fuente
Este funciona. Una cadena vacía en io.of ('') funciona sin espacios de nombres.
Király István
@ KirályIstván No he investigado esto por un tiempo, pero creo que puedes eliminar por completo la of()llamada encadenada en ese caso.
rppc
1

Para el modo de clúster, usando redis-adapter

io.in(<room>).clients(function(err, clients) {

});

Como cada socket es en sí mismo una habitación, entonces uno puede encontrar si existe un socket usando el mismo.

Anuj Nautiyal
fuente
0

Aquí hay una forma rápida de convertir el hash de los sockets conectados de un espacio de nombres a una matriz usando generadores ES6 (se aplica a socket.io> = v1.0.0):

io.on('connection', function(socket) {
  var hash = io.of('/').connected
  var list = null

  hash[Symbol.iterator] = function*() {
    // for..of loop to invoke Object.keys() default iterator
    // to get the array values instead of the keys
    for(var id of Object.keys(hash)) yield hash[id]
  }

  list = [...hash]
  console.log(Array.isArray(list)) // true
})
Morgan
fuente
0

No sé si esto todavía va. Pero algo como esto es lo que terminé usando (mantengo un objeto de sesión en cada socket conectado, que a su vez contiene el nombre de usuario y otra información:

var connectedUsers = Object.keys(io.sockets.connected).map(function(socketId) {
    return io.sockets.connected[socketId].session.username;
});
diazd2
fuente
0

Si el proyecto tiene un cluster socket.io, esto significa se está utilizando el adaptador socket.io-redis .

Si el caso es el anterior, se debe aplicar el proceso de identificación de todos los enchufes conectados a través del adaptador socket.io-redis . Los siguientes ejemplos podrían usarse para esto;

io.of('/').adapter.clients(function (err, clients) {
  console.log("clients: ", clients); // an array containing all connected socket ids
});


io.of('/').adapter.allRooms(function (err, rooms) {
  console.log("all rooms: ", rooms);
});

Visite la página socket.io-redis github para obtener más detalles.

efkan
fuente
0

[email protected]

Usé Object.Keys para conectar la matriz de socket. Luego, en la misma matriz, itere con la función de mapa para construir una nueva matriz de objetos

var connectedUsers = Object.keys(io.sockets.connected).map(function(socketId) {
    return { socket_id : socketId, socket_username: io.sockets.connected[socketId].username };
});

// test
console.log(connectedUsers);

Quizás esta respuesta pueda ayudar a obtener la matriz de id / nombre de usuario del socket.

jvaldezb
fuente
1
Hola, ¿puedes explicar en inglés cómo soluciona el problema? De esta manera, no será solo una respuesta de solo código. ¡Gracias!
Max von Hippel
0

v.10

var clients = io.nsps['/'].adapter.rooms['vse'];
/* 
'clients' will return something like:
Room {
sockets: { '3kiMNO8xwKMOtj3zAAAC': true, FUgvilj2VoJWB196AAAD: true },
length: 2 }
*/
var count = clients.length;  // 2
var sockets = clients.map((item)=>{  // all sockets room 'vse'
       return io.sockets.sockets[item];
      });
sample >>>
var handshake  = sockets[i].handshake; 
handshake.address  .time .issued ... etc.
Arca iv
fuente
1
Sería bueno si pudiera agregar algún contexto por qué 'Esta es la mejor manera' y cómo su respuesta agrega algo a todas las respuestas anteriores. El código es algo, pero una respuesta también debería tener alguna explicación. Como puede ver, hay muchas otras respuestas a esta pregunta. Su respuesta debe aportar algo más al tema, de lo contrario, es redundante.
Nathan Ripert el
Con socket.io 2.1.1 , entiendo TypeError: clients.map is not a functiony, aunque parece prometedor, no estoy completamente seguro de lo que logrará el ejemplo anterior: esperaba que creara automáticamente una matriz de objetos de cliente con nombres de usuario incluidos :).
user1063287