Socket.IO - come posso ottenere un elenco di socket / client connessi?


159

Sto cercando di ottenere un elenco di tutti i socket / client attualmente connessi.

io.sockets purtroppo non restituisce un array.

So che potrei mantenere il mio elenco usando un array, ma non credo che questa sia una soluzione ottimale per 2 motivi:

  1. Ridondanza. Socket.IO conserva già una copia di questo elenco.

  2. Socket.IO fornisce il metodo per impostare valori di campo arbitrari per i client (cioè:), socket.set('nickname', 'superman')quindi dovrei tenere il passo con queste modifiche se dovessi mantenere il mio elenco.

Aiuto?


Non puoi semplicemente convertire io.socket in un array?
mak

2
In 0.7.6 io.sockets.sockets è un semplice oggetto hash id => socket
mak

1
L'ho notato, ma si comporta in modo strano (non sembra oggetti socket standard). Ad esempio, ho provato: pastebin.com/fxuzVckS ma sta dicendo che l'oggetto socket non contiene un metodo 'get'.
Andy Hin,

3
socketè id, io.sockets.sockets[socket]è il socket.
mak

2
Il primo argomento è erre se stai usando l'archivio di memoria è sempre null. .get('nickname', function(err, nickname) { ... })
mak

Risposte:


173

In Socket.IO 0.7 hai un clients metodo negli spazi dei nomi, questo restituisce un array di tutti i socket collegati.

API per nessuno spazio dei nomi:

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

Per uno spazio dei nomi

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

Spero che questo aiuti qualcuno in futuro

NOTA: questa soluzione funziona SOLO con la versione precedente alla 1.0


AGGIORNATO 2020 mar 06

Da 1.xe versioni successive, fare riferimento a questo link: ottenere quante persone si trovano in una chat room in socket.io


3
Penso che abbiano abbandonato il metodo client in 1.0 ... al momento lo
sto verificando

7
Hanno lasciato cadere quasi tutto in 1.0 in quanto è una riscrittura completa. Ma come 1.0 è inedito da anni. In 1.0 devi usare l' connectedoggetto dello spazio dei nomi.
°,

6
@ 3rdEden, qual è la sintassi per l'utilizzo dell'oggetto connesso dello spazio dei nomi? var clients = io.sockets.connected();ovviamente non funziona. Grazie
Kaya Toast il


TypeError: fn.bind non è una funzione
Iman Marashi il

101

Socket.io 1.4

Object.keys(io.sockets.sockets); ti dà tutte le prese collegate.

Socket.io 1.0 A partire da socket.io 1.0, la risposta effettivamente accettata non è più valida. Quindi ho fatto una piccola funzione che uso come soluzione temporanea:

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 per Nessuno spazio dei nomi diventa

// 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 per uno spazio dei nomi diventa:

// 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');

Vedi anche questa domanda correlata , in cui do una funzione che restituisce le prese per una determinata stanza.

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 per nessuno spazio dei nomi :

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

Per uno spazio dei nomi

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

Nota: poiché sembra che l'API socket.io sia soggetta a interruzioni e alcune soluzioni si basino sui dettagli di implementazione, potrebbe essere una questione di tracciare i client da soli:

var clients = [];

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

    client.on('disconnect', function() {
        clients.splice(clients.indexOf(client), 1);
    });
});

3
Grazie per questo. Sono sorpreso che abbiano rimosso questa funzionalità.
Tyler Scott,

1
@TylerScott Anche a me, soprattutto perché questo non è trattato nella loro guida alla migrazione (a meno che non mi manchi qualcosa). socket.io/docs/migrating-fr-0-0
nha

@nha, questo non funziona per me ma restituisce un array di numeri interi, come 0, 1 e 2 ecc. anziché un array di socket. Qualche idea?
ThePixelPony,

che ne dici di più nodi? perché utilizzo più nodi con redis store
John Nguyen il

3
@nha rispondi esattamente, ma non funziona per più nodi con il server di archiviazione redis. dal processo a 1 nodo, non è possibile controllare il socket collegato o meno utilizzando ns.connected [id]
John Nguyen

46

Dopo socket.io 1.0 non possiamo usare

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

più. Invece puoi usare quanto segue

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
}

3
cambio avar clients_in_the_room = io.sockets.adapter.rooms[roomId].sockets
Fábio Zangirolami il

37

Utilizzando Socket.IO 1.x:

Ottieni array dei client connessi:

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

Ottieni il numero di client connessi:

io.engine.clientsCount // => 2
io.eio.clientsCount    // => 2

32

Molto semplice in socket.io 1.3:

io.sockets.sockets- è un array contenente gli oggetti socket collegati. Se hai memorizzato il nome utente in ciascun socket, puoi fare:

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

Boom. Hai i nomi di tutti gli utenti connessi.


2
Grazie! +1 per semplicità. Sai se c'è qualche differenza tra questo metodo e, diciamo, la risposta di Joseph Dykstra? (Object.keys(io.engine.clients)
cyclingLinguist

4
Questo non funziona su v1.4.5. Sto ancora lavorando su una soluzione
Nuno Furtado,

l'hai trovato? \
ocram

2
TypeError: io.sockets.sockets.map non è una funzione
Király István

23

Ho attraversato questo dolore oggi. Socket.io sarà molto meglio se potessero fare una documentazione adeguata per la loro API.

Ad ogni modo, ho provato a esaminare io.socket e ho trovato una serie di opzioni che possiamo usare:

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

Inoltre, si noti che quando si utilizza socket.io con namespace, i metodi di cui sopra si interrompono poiché io.socket diventa un array anziché un oggetto. Per risolvere, basta sostituire io.socket con io (cioè io.sockets.connected diventa io.connected, io.sockets.adapter.rooms diventa io.adapter.rooms ...)

Testato su socket.io 1.3.5


1
@ Зелёный Funzionerà se non stai usando lo spazio dei nomi. Se si utilizza lo spazio dei nomi, passare a io.server.eio.clientsCount
Thanh Nguyen il

2
Sì, la documentazione ufficiale potrebbe essere migliorata così tanto
CodeAndCats

18

Versione +2.0

Nella versione +2.0 si specifica lo spazio dei nomi / room / node contro cui si esegue la query.

Come per la trasmissione, l'impostazione predefinita è tutti i client dallo spazio dei nomi predefinito ('/'):

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

Ottiene un elenco di ID client collegati a uno spazio dei nomi specifico (su tutti i nodi, se applicabile).

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

Un esempio per ottenere tutti i client nella stanza dello spazio dei nomi:

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

Questo è tratto dalla documentazione ufficiale: Socket.IO Server-API


1
c'è un modo per visualizzare tutti gli oggetti socket ? ad esempio, se aggiungo una socket.usernameproprietà a ciascun socket al momento della connessione, esiste un modo per visualizzare tutti questi oggetti socket (incluse le proprietà personalizzate che aggiungo a ciascun socket)? (per riferimento, sto attualmente utilizzando una variabile oggetto globale per memorizzare ulteriori informazioni sui socket quando un client si connette - quindi non chiedo come configurarlo - sono solo interessato a sapere se esiste un modo per visualizzare tutti gli oggetti socket per impostazione predefinita) .
user1063287

1
hmm, per questa risposta , i che si può vedere tutti i socket connessi con console.log(io.sockets.connected)- sembra essere un oggetto in cui ogni valore della proprietà è un "oggetto socket" che contiene queste proprietà nsp, server, adaptor, id(una stringa), client, conn, rooms, acks, connected, disconnected, handshake, fns, flags, _rooms, _events, _eventsCounte, infine, usernameche è la proprietà personalizzata aggiungo ad ogni presa sulla connessione.
user1063287

17

Penso che possiamo accedere all'oggetto socket dal server e tu puoi assegnare il nickname e puntare il suo id 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");
    });    
});

disconnect, rimuovi il nickname da io.sockets.sockets.


qual è lo scopo di 'client.on'? Puoi usare il tuo codice in questo modo (accettando solo dati da 1 socket) ?: io.sockets.sockets [sock_id] .on ('newmessage', function (data) {console.log (data)});
The Hawk,

9

Questo è il modo migliore per accedervi in ​​socket.io 1.3

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


per favore, lasciami condividere questo esempio, 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

Per chiunque desideri solo un COUNT dei client connessi credo che questo lo farà:

io.sockets.manager.server.connections


non viene conteggiato, verificato il client connesso. (un po 'di più)
mrzmyr

5
per ottenere un conteggio accurato utilizzareio.sockets.clients().length
Ivo

2
Attualmente entrambi io.sockets.manager.server.connectionse io.sockets.clients().lengthnon funzionano. Questo ha funzionato per me - solo per conteggio - io.engine.clientsCounte per l'elenco dei clienti - io.engine.clientsCount. Da allora è rimasto così per oltre 3 anni. Sembra un modo affidabile per ottenere le informazioni sulla connessione. (Basato sulla risposta di Joseph Dykstra)
Aswin Ramakrishnan,

5

Socket.io 1.4.4

Codice di esempio per te.

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;
        });
    }

Penso che aiuterà qualcuno a bloccare questo codice.


4

In Socket.IO 1.4

Per ottenere l'array di Tutti gli utenti connessi:

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

Per ottenere il conteggio di tutti i client:

var clientsCount = io.engine.clientsCount ; // This will return the count of connected clients

Confermo che funziona nella versione 1.5.1 di socket.io
Sébastien il

3

A partire da socket.io 1.5, notare la modifica da indexOf che sembra essere deprezzata e sostituita da 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;
}

Per socket.io versione 2.0.3, funziona il seguente codice:

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;
}

non puoi immaginare quanto dolore mi hai salvato
nicholaswmin,

ma la versione di socket.io non è ancora 1.5! Sono le 1.4.8 ora
leszek.hanusz,

@MoleIsKing Obrigado amigo!

2

su socket.io 1.3 l'ho realizzato in 2 righe

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

2

Socket.io 1.7.3 (+):

funzione getConnectedList ()
{
    let list = []
    
    per (lascia il client in io.sockets.connected)
    {
        list.push (client)
    }
    
    lista di ritorno
}

console.log (getConnectedList ())

// restituisce ['yIfhb2tw7mxgrnF6AAAA', 'qABFaNDSYknCysbgAAAB']


2

Per la versione 2.3 funziona e ti darà anche il socket , mi sembra che socketIo stia cambiando troppo velocemente e con troppa documentazione leggibile dopo averlo usato per un po '.

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);
    }
});

tuttavia questo non sembra giusto, dato che in qualche modo ho sempre questa sensazione con la presa Io


1
sto iniziando a pensare che sia una libreria di immondizia. l'unica cosa che fa è quella di trasferire senza problemi molti tipi di dati (json, binari, ecc.) altrimenti l'intera architettura è una schifezza e non si ridimensiona oltre l'app di chat 1 su 1
Muhammad Umer,

1

Credo che tu possa accedervi dalla proprietà del gestore del socket?

var handshaken = io.manager.handshaken;
var connected = io.manager.connected;
var open = io.manager.open;
var closed = io.manager.closed;

La risposta di 3rdEden non ha funzionato per me in quanto vi sono problemi con l'array che restituisce client disconnessi, il che comporta un errore. Object.keys (io.manager.open) .length si è rivelato il conteggio più affidabile nella mia esperienza. io.of ('/ namespace'). manager.open se usi gli spazi dei nomi.
Wes Johnson,

1

Vedo molte buone risposte qui e molte dove abbastanza utili ma non proprio quello di cui avevo bisogno. Sto usando socket per una funzione pubsub in cui un cliente interessato può ascoltare qualsiasi modifica in un dato record.

Il mio problema specifico era che lo stesso socket si univa più volte alla stessa stanza. La soluzione a ciò era verificare se la presa aveva già la stanza all'interno della sua proprietà.

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");
}

Spero che questo aiuti qualcuno.


Penso che sia possibile evitare quell'affermazione "if", se si fa in modo che il client entri nella stanza dopo la connessione socket.
Chayemor,

Da dove viene myObj? Come sei arrivato a quel valore?
Michael Draper,

@MikeDraper myObject è il record in un database che funge da canale. Ciò risolve il caso in cui si desidera che tutti i client vengano aggiornati ogni volta che si verifica una modifica nel database, ad esempio un utente aggiorna il suo nome e tutti i client connessi ottengono un aggiornamento. Quindi creo una stanza per quell'ID istanza, dato che è unica (BSON). È un valore molto specifico per il mio caso d'uso, quindi mi dispiace se ho causato confusione. Fammi sapere se hai bisogno di aiuto :)
Gus Ortiz,

@JMR a causa della natura della mia app è successo che un socket è stato sottoscritto più di una volta, ecco perché ho dovuto aggiungere quel controllo.
Gus Ortiz,

1

Questo è il modo più semplice in Socket.IO 1.0+, se non si utilizzano spazi dei nomi o stanze.

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

Questo esamina lo spazio dei nomi predefinito e determina la lunghezza dell'array socket, senza bisogno di usare Object.keys()


1

Dalla versione 1.5.1, sono in grado di accedere a tutti i socket in uno spazio dei nomi 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...
    }
});

Per qualche ragione, stanno usando un oggetto semplice anziché un array per memorizzare gli ID socket.


Questo funziona. Una stringa vuota in io.of ('') funziona senza spazi dei nomi.
Király István,

@ KirályIstván Non mi occupo di questo da un po 'di tempo, ma penso che puoi rimuovere completamente la of()chiamata incatenata in quel caso.
rppc,

1

Per la modalità cluster, usando redis-adapter

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

});

Poiché ogni socket è esso stesso una stanza, si può scoprire se esiste una presa usando la stessa.


0

Ecco un modo rapido per convertire l'hash dei socket connessi da uno spazio dei nomi in un array usando generatori ES6 (si applica 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
})

0

Non so se questo sta ancora andando. Ma qualcosa del genere è quello che ho finito per usare (tengo un oggetto sessione su ciascun socket collegato, che a sua volta contiene il nome utente e altre informazioni:

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

0

Se il progetto ha una socket.io gruppo Questo significa socket.io-Redis adattatore è in uso.

In questo caso, è necessario applicare il processo di identificazione di tutti i socket collegati tramite l' adattatore socket.io-redis . Gli esempi seguenti potrebbero essere usati per questo;

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);
});

Per ulteriori dettagli, visitare la pagina github di socket.io-redis .


0

socket.io@1.7.3

Ho usato Object.Keys per collegare l'array di socket. Quindi, nello stesso array, scorrere con la funzione map per creare un nuovo array di oggetti

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);

Forse questa risposta può aiutare a ottenere l'array id socket / username.


1
Ciao, puoi spiegare in inglese come questo risolve il problema? In questo modo non sarà solo una risposta di solo codice. Grazie!
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.

1
Sarebbe bello se potessi aggiungere un contesto perché "Questo è il modo migliore" e come la tua risposta aggiunge qualcosa a tutte le molte risposte sopra. Il codice è qualcosa, ma una risposta dovrebbe anche avere qualche spiegazione. Come puoi vedere ci sono molte altre risposte a questa domanda. La tua risposta deve portare qualcosa in più sull'argomento, altrimenti è ridondante.
Nathan Ripert,

Con socket.io 2.1.1 , capisco TypeError: clients.map is not a functione sebbene sembri promettente, non sono del tutto sicuro di ciò che otterrà l'esempio sopra - speravo che avrebbe creato automagicamente una matrice di oggetti client con nomi utente inclusi :).
user1063287
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.