node.js - rooms - Socket.IO: ¿cómo obtengo una lista de enchufes/clientes conectados?
socket.io example (25)
Socket.io 1.7.3 (+):
function getConnectedList () { let list = [] for ( let client in io.sockets.connected ) { list.push(client) } return list } console.log( getConnectedList() ) // returns [ ''yIfhb2tw7mxgrnF6AAAA'', ''qABFaNDSYknCysbgAAAB'' ]
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 dos razones:
Redundancia. Socket.IO ya tiene una copia de esta lista.
Socket.IO proporciona un método para establecer valores de campo arbitrarios para los clientes (es decir:
socket.set(''nickname'', ''superman'')
), así que tendría que estar al día con estos cambios si tuviera que mantener mi propia lista.
¿Ayuda?
Versión +2.0
En la versión +2.0 especifica el espacio de nombres / sala / nodo sobre el que está consultando.
Al igual que con la radiodifusión, el valor predeterminado es todos los clientes del espacio de nombre 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 cliente conectadas al espacio de nombre 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
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 los ID de los sockets.
A partir de socket.io 1.5, observe el cambio de indexOf que parece depreciado y reemplazado 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;
}
Creo que podemos acceder al objeto de socket desde el servidor, y puede asignar el alias, y apuntar 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");
});
});
Al disconnect
, elimine el sobrenombre de io.sockets.sockets
.
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;
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
}
En Socket.IO 0.7 tiene un método de clients
en los espacios de nombres, esto devuelve una matriz de todos los sockets conectados.
API para no 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 SÓLO funciona con la versión anterior a la 1.0
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 conteo de todos los clientes:
var clientsCount = io.engine.clientsCount ; // This will return the count of connected clients
Esta es la forma más simple en Socket.IO 1.0+, si no está usando espacios de nombres o salas.
io.nsps["/"].sockets.length
Esto mira el espacio de nombres predeterminado y determina la longitud de la matriz de sockets, sin la necesidad de utilizar Object.keys()
Esta es la mejor manera de acceder a ella en socket.io 1.3
Object.keys(socket.adapter.rooms[room_id])
Esta es una forma rápida de convertir el hash de los sockets conectados de un espacio de nombres a un array que usa 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
})
He pasado por este dolor hoy. Socket.io será mucho mejor si pudieran hacer una documentación adecuada para su API.
De todos modos, traté de buscar en io.sockets y encontré una cantidad de 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 al usar socket.io con namespace, los métodos anteriores se romperán ya que io.sockets se convierte en una matriz en lugar de en un objeto. Para resolver, simplemente reemplace io.sockets por io (es decir, io.sockets.connected se convierte io.connected, io.sockets.adapter.rooms se convierte en io.adapter.rooms ...)
Probado en socket.io 1.3.5
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. Usted tiene los nombres de todos los usuarios conectados.
No sé si esto todavía está sucediendo. Pero algo así es lo que terminé usando (guardo 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;
});
Para cualquiera que solo quiera un COUNT de clientes conectados, creo que esto lo hará:
io.sockets.manager.server.connections
Para el modo de clúster, usando redis-adapter
io.in(<room>).clients(function(err, clients) {
});
Como cada zócalo es en sí mismo una habitación, uno puede encontrar si existe un zócalo usando el mismo.
Si el proyecto tiene un clúster socket.io, esto significa que se está utilizando el adaptador socket.io-redis .
Si el caso es similar al anterior, se debe aplicar el proceso de identificación de sockets conectado a través del adaptador socket.io-redis . Los siguientes ejemplos pueden ser utilizados 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);
});
Por favor visite la página de socket.io-redis github para más detalles.
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 bloquear este código.
Usando Socket.IO 1.x:
Obtener una matriz de los clientes conectados:
io.engine === io.eio // => true
Object.keys(io.engine.clients) // => [ ''US8AxrUrrDF_G7ZUAAAA'', ''Ov2Ca24Olkhf2NHbAAAB'' ]
Object.keys(io.eio.clients) // => [ ''US8AxrUrrDF_G7ZUAAAA'', ''Ov2Ca24Olkhf2NHbAAAB'' ]
Obtenga la cantidad de clientes conectados:
io.engine.clientsCount // => 2
io.eio.clientsCount // => 2
Veo muchas buenas respuestas aquí y muchas fueron bastante útiles pero no exactamente lo que necesitaba. Estoy usando sockets para una función pubsub en la que un cliente interesado puede escuchar cualquier cambio en un registro determinado.
Mi problema específico era que el mismo socket se estaba uniendo a la misma sala varias veces. La solución a esto era verificar si el socket ya tenía la habitación dentro de la propiedad de las habitaciones.
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.
en socket.io 1.3 lo he logrado en 2 líneas
var usersSocketIds = Object.keys(chat.adapter.rooms[''room name'']);
var usersAttending = _.map(usersSocketIds, function(socketClientId){ return chat.connected[socketClientId] })
Para la versión 2.3 esto funciona y también obtendrá el socket , me parece que socketIo está cambiando demasiado rápido y con 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 esta sensación con socket Io de alguna manera
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 aceptada real ya no es válida. Así que hice una pequeña función que utilizo como 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 for No namespace 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'');
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 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 no 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`
Nota: Dado que parece que la API de socket.io es propensa a romperse, y alguna solución depende de los detalles de la implementación, podría ser cuestión de hacer un seguimiento de 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);
});
});
var Client = require("socket.io").listen(8888); //port listening
//This is the best way.
var connection = Client.engine.clientsCount