Socket.IO - Comment obtenir une liste des sockets / clients connectés?


159

J'essaye d'obtenir une liste de toutes les sockets / clients qui sont actuellement connectés.

io.sockets ne renvoie pas de tableau, malheureusement.

Je sais que je pourrais garder ma propre liste en utilisant un tableau, mais ne pense pas que ce soit une solution optimale pour 2 raisons:

  1. Redondance. Socket.IO conserve déjà une copie de cette liste.

  2. Socket.IO fournit une méthode pour définir des valeurs de champ arbitraires pour les clients (c'est-à-dire:), socket.set('nickname', 'superman')donc je devrais suivre ces changements si je devais maintenir ma propre liste.

Aidez-moi?


Ne pouvez-vous pas simplement convertir io.sockets en un tableau?
mak

2
Dans 0.7.6 io.sockets.sockets est un simple objet de hachage id => socket
mak

1
J'ai remarqué cela, mais cela agit de manière étrange (ne ressemble pas à des objets socket standard). Par exemple, j'ai essayé: pastebin.com/fxuzVckS mais cela dit que l'objet socket ne contient pas de méthode «get».
Andy Hin

3
socketest id, io.sockets.sockets[socket]est la socket.
mak

2
Le premier argument est erret si vous utilisez le stockage de mémoire, c'est toujours null. .get('nickname', function(err, nickname) { ... })
mak

Réponses:


173

Dans Socket.IO 0.7, vous avez une clientsméthode sur les espaces de noms, cela renvoie un tableau de toutes les sockets connectées.

API pour aucun espace de noms:

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

Pour un espace de noms

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

Espère que cela aide quelqu'un à l'avenir

REMARQUE: cette solution fonctionne UNIQUEMENT avec la version antérieure à 1.0


MISE À JOUR 2020 Mar 06

À partir de 1.x et au-dessus, veuillez vous référer à ce lien: obtenir combien de personnes sont dans une salle de chat dans socket.io


3
Je pense qu'ils ont abandonné la méthode des clients dans la version 1.0 ... il suffit de vérifier cela pour le moment ...
marksyzm

7
Ils ont presque tout abandonné dans la version 1.0 car il s'agit d'une réécriture complète. Mais comme 1.0 n'a pas été publié depuis des années. Dans la version 1.0, vous devez utiliser l' connectedobjet de l'espace de noms.
3rdEden

6
@ 3rdEden, quelle est la syntaxe pour utiliser l'objet connecté de l'espace de noms? var clients = io.sockets.connected();ne fonctionne évidemment pas. Merci
Kaya Toast

5
À partir de 1.x et au-dessus: stackoverflow.com/questions/9352549/…
Musa Haidari

TypeError: fn.bind n'est pas une fonction
Iman Marashi

101

Socket.io 1.4

Object.keys(io.sockets.sockets); vous donne toutes les prises connectées.

Socket.io 1.0 Depuis socket.io 1.0, la réponse acceptée n'est plus valide. J'ai donc créé une petite fonction que j'utilise comme solution temporaire:

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 devient

// 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 pour un espace de noms devient:

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

Voir aussi cette question connexe , dans laquelle je donne une fonction qui renvoie les sockets pour une pièce donnée.

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 pour aucun espace de noms :

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

Pour un espace de noms

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

Remarque: comme il semble que l'API socket.io est susceptible de se casser et que certaines solutions reposent sur des détails d'implémentation, il peut s'agir de suivre les clients vous-même:

var clients = [];

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

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

3
Merci pour ça. Je suis surpris qu'ils aient retiré cette fonctionnalité.
Tyler Scott

1
@TylerScott Moi aussi, d'autant plus que cela n'est pas couvert dans leur guide de migration (sauf si je manque quelque chose). socket.io/docs/migrating-from-0-9
nha

@nha, cela ne fonctionne pas pour moi mais renvoie un tableau d'entiers, comme 0, 1 et 2, etc. au lieu d'un tableau de sockets. Des idées?
ThePixelPony

que diriez-vous pour plusieurs nœuds? parce que j'utilise plusieurs nœuds avec redis store
John Nguyen

3
@nha vous répondez est exactement, mais cela ne fonctionne pas pour plusieurs nœuds avec le serveur de magasin Redis. à partir d'un processus de nœud, vous ne pouvez pas vérifier le socket connecté ou non en utilisant ns.connected [id]
John Nguyen

46

Après socket.io 1.0, nous ne pouvons pas utiliser

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

plus. Au lieu de cela, vous pouvez utiliser ce qui suit

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
je change pourvar clients_in_the_room = io.sockets.adapter.rooms[roomId].sockets
Fábio Zangirolami

37

Utilisation de Socket.IO 1.x:

Obtenez un tableau des clients connectés:

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

Obtenez le nombre de clients connectés:

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

32

Très simple dans socket.io 1.3:

io.sockets.sockets- est un tableau contenant les objets socket connectés. Si vous avez stocké le nom d'utilisateur dans chaque socket, vous pouvez faire:

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

Boom. Vous avez les noms de tous les utilisateurs connectés.


2
Merci! +1 pour la simplicité. Savez-vous s'il y a une différence entre cette méthode et, disons, la réponse de Joseph Dykstra? (Object.keys(io.engine.clients)
cyclingLinguist

4
Cela ne fonctionne pas sur la v1.4.5. Je travaille toujours sur une solution
Nuno Furtado

l'avez-vous trouvé? \
ocram

2
TypeError: io.sockets.sockets.map n'est pas une fonction
Király István

23

J'ai traversé cette douleur aujourd'hui. Socket.io sera bien meilleur s'ils pouvaient créer une documentation appropriée pour leur API.

Quoi qu'il en soit, j'ai essayé de regarder dans io.sockets et j'ai trouvé un certain nombre d'options que nous pouvons utiliser:

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

Notez également que lorsque vous utilisez socket.io avec namespace, les méthodes ci-dessus seront interrompues car io.sockets devient un tableau au lieu d'un objet. Pour résoudre, remplacez simplement io.sockets par io (c'est-à-dire que io.sockets.connected devient io.connected, io.sockets.adapter.rooms devient io.adapter.rooms ...)

Testé sur socket.io 1.3.5


1
@ Зелёный Cela fonctionnera si vous n'utilisez pas d'espace de noms. Si vous utilisez un espace de noms, passez à io.server.eio.clientsCount
Thanh Nguyen

2
Oui, la documentation officielle pourrait être tellement améliorée
CodeAndCats

18

Version +2.0

Dans la version +2.0, vous spécifiez l'espace de noms / la salle / le nœud sur lequel vous interrogez.

Comme pour la diffusion, la valeur par défaut est tous les clients de l'espace de noms par défaut ('/'):

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

Obtient une liste des ID client connectés à un espace de noms spécifique (sur tous les nœuds, le cas échéant).

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

Un exemple pour obtenir tous les clients dans la salle de l'espace de noms:

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

Ceci provient de la documentation officielle: Socket.IO Server-API


1
existe-t-il un moyen de visualiser tous les objets socket ? Par exemple, si j'ajoute une socket.usernamepropriété à chaque socket lors de la connexion, y a-t-il un moyen pour afficher tous ces objets socket (y compris les propriétés personnalisées que j'ajoute à chaque socket)? (pour référence, j'utilise actuellement une variable d'objet globale pour stocker des informations de socket supplémentaires lorsqu'un client se connecte - donc je ne demande pas comment configurer cela - juste intéressé à savoir s'il existe un moyen d'afficher tous les objets de socket par `` défaut '') .
user1063287

1
hmm, par cette réponse , je pense que vous pouvez voir toutes les prises connectés avec console.log(io.sockets.connected)- il semble être un objet où chaque valeur de la propriété est un « objet socket » qui contient ces propriétés nsp, server, adaptor, id(une chaîne), client, conn, rooms, acks, connected, disconnected, handshake, fns, flags, _rooms, _events, _eventsCountet enfin usernamequi est la propriété personnalisée i ajouter à chaque prise de connexion.
user1063287

17

Je pense que nous pouvons accéder à l'objet socket depuis le serveur, et vous pouvez attribuer le surnom et pointer son identifiant 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");
    });    
});

Le disconnectveuillez supprimer le pseudo de io.sockets.sockets.


quel est le but de «client.on»? Pouvez-vous utiliser votre code comme ceci (n'accepter que les données d'une seule socket)?: Io.sockets.sockets [sock_id] .on ('newmessage', function (data) {console.log (data)});
The Hawk

9

C'est le meilleur moyen d'y accéder dans socket.io 1.3

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


s'il vous plaît laissez-moi partager cet exemple, 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

Pour tous ceux qui veulent juste un COUNT des clients connectés, je pense que cela le fera:

io.sockets.manager.server.connections


n'est pas le nombre de clients connectés, testé. (peu plus)
mrzmyr

5
afin d'obtenir une utilisation précise du décompteio.sockets.clients().length
Ivo

2
Actuellement, les deux io.sockets.manager.server.connectionset io.sockets.clients().lengthne fonctionnent pas. Cela a fonctionné pour moi - pour le décompte seulement - io.engine.clientsCountet pour la liste des clients - io.engine.clientsCount. Depuis, il est resté ainsi pendant plus de 3 ans. Cela semble être un moyen fiable d'obtenir les informations de connexion. (Basé sur la réponse de Joseph Dykstra)
Aswin Ramakrishnan

5

Socket.io 1.4.4

Exemple de code pour vous.

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

Je pense que cela aidera quelqu'un à bloquer ce code.


4

Dans Socket.IO 1.4

Pour obtenir le tableau de tous les utilisateurs connectés:

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

Pour obtenir le nombre de tous les clients:

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

Je confirme que cela fonctionne dans la version 1.5.1 de socket.io
Sébastien

3

À partir de socket.io 1.5, notez le changement de indexOf qui semble déprécié, et remplacé par 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;
}

Pour socket.io version 2.0.3, le code suivant fonctionne:

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

vous ne pouvez pas imaginer combien de douleur vous m'avez sauvé
nicholaswmin

mais la version socket.io n'est pas encore 1.5! Il est maintenant 1.4.8
leszek.hanusz

@MoleIsKing Obrigado amigo!

2

sur socket.io 1.3 j'ai accompli cela en 2 lignes

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 (+):

fonction getConnectedList ()
{
    let list = []
    
    for (laissez le client dans io.sockets.connected)
    {
        list.push (client)
    }
    
    liste de retour
}

console.log (getConnectedList ())

// renvoie ['yIfhb2tw7mxgrnF6AAAA', 'qABFaNDSYknCysbgAAAB']


2

Pour la version 2.3, cela fonctionne et vous obtiendrez le socket aussi , il me semble que socketIo change trop vite et trop avec une documentation peu lisible après l'avoir utilisé pendant un certain temps.

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

toujours cela ne me semble pas bien, car j'ai toujours ce sentiment avec socket Io en quelque sorte


1
Je commence à penser que c'est une bibliothèque d'ordures. la seule chose qu'il fait correctement transfère de manière transparente de nombreux types de données (json, binaires, etc.), sinon toute l'architecture est de la merde et ne passe pas au-delà de l'application de chat 1 sur 1
Muhammad Umer

1

Je crois que vous pouvez y accéder à partir de la propriété manager du socket?

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

La réponse de 3rdEden n'a pas fonctionné pour moi car il y a des problèmes avec le tableau renvoyant des clients déconnectés, ce qui annule le décompte. Object.keys (io.manager.open) .length s'est avéré être le décompte le plus fiable de mon expérience. io.of ('/ namespace'). manager.open si vous utilisez des espaces de noms.
Wes Johnson

1

Je vois beaucoup de bonnes réponses ici et beaucoup étaient très utiles mais pas tout à fait ce dont j'avais besoin. J'utilise des sockets pour une fonctionnalité pubsub dans laquelle un client intéressé peut écouter les modifications dans un enregistrement donné.

Mon problème spécifique était que la même prise rejoignait la même pièce plusieurs fois. La solution à cela était de vérifier si la prise avait déjà la pièce à l'intérieur de sa propriété rooms.

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

J'espère que cela aide quelqu'un.


Je pense qu'il est possible d'éviter cette déclaration «si», si vous obligez le client à rejoindre la salle lors de la connexion par socket.
Chayemor

D'où vient myObj? Comment en êtes-vous arrivé à cette valeur?
Michael Draper

@MikeDraper myObject est l'enregistrement dans une base de données qui agit comme un canal. Cela résout le cas où vous souhaitez que tous vos clients soient mis à jour chaque fois qu'un changement dans la base de données se produit, par exemple un utilisateur met à jour son nom et tous les clients connectés reçoivent une mise à jour. Je crée donc une salle pour cet identifiant d'instance, étant donné qu'il est unique (BSON). C'est une valeur très spécifique pour mon cas d'utilisation, donc je suis désolé si j'ai causé une confusion. Faites-moi savoir si vous avez besoin d'aide :)
Gus Ortiz

@JMR en raison de la nature de mon application, il est arrivé qu'une socket soit abonnée plus d'une fois, c'est pourquoi j'ai dû ajouter cette vérification.
Gus Ortiz

1

C'est le moyen le plus simple dans Socket.IO 1.0+, si vous n'utilisez pas d'espaces de noms ou de salles.

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

Cela examine l'espace de noms par défaut et détermine la longueur du tableau de sockets, sans avoir besoin d'utiliser Object.keys()


1

Depuis la version 1.5.1, je peux accéder à toutes les sockets d'un espace de noms avec:

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

Pour une raison quelconque, ils utilisent un objet simple au lieu d'un tableau pour stocker les ID de socket.


Celui-ci fonctionne. Une chaîne vide dans io.of ('') fonctionne sans espaces de noms.
Király István

@ KirályIstván Je n'ai pas examiné cela depuis un moment maintenant, mais je pense que vous pouvez supprimer complètement l' of()appel en chaîne dans ce cas.
rppc

1

Pour le mode cluster, à l'aide de l'adaptateur redis

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

});

Comme chaque socket est elle-même une pièce, on peut donc trouver si une prise existe en utilisant la même.


0

Voici un moyen rapide de convertir le hachage des sockets connectés d'un espace de noms en un tableau à l'aide de générateurs ES6 (s'applique à 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

Je ne sais pas si cela continue. Mais quelque chose comme ça, c'est ce que j'ai fini par utiliser (je garde un objet de session sur chaque socket connectée, qui à son tour contient le nom d'utilisateur et d'autres informations:

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

0

Si le projet a un cluster socket.io , cela signifie que l' adaptateur socket.io-redis est utilisé.

Si le cas est similaire à celui ci-dessus, l'obtention du processus d'identification de tous les sockets connectés doit être appliquée via l' adaptateur socket.io-redis . Les exemples ci-dessous peuvent être utilisés pour cela;

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

Veuillez visiter la page github de socket.io-redis pour plus de détails.


0

socket.io@1.7.3

J'ai utilisé Object.Keys pour connecter le tableau de socket. Ensuite, dans le même tableau, itérez avec la fonction de carte pour créer un nouveau tableau d'objets

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

Peut-être que cette réponse peut aider à obtenir le tableau id / nom d'utilisateur de socket.


1
Salut - pouvez-vous expliquer en anglais comment cela résout le problème? De cette façon, ce ne sera pas seulement une réponse de code uniquement. Merci!
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
Ce serait bien si vous pouviez ajouter un peu de contexte pourquoi «C'est la meilleure façon» et comment votre réponse ajoute quelque chose à toutes les nombreuses réponses ci-dessus. Le code est quelque chose, mais une réponse doit aussi avoir une explication. Comme vous pouvez le voir, il existe de nombreuses autres réponses à cette question. Votre réponse doit apporter quelque chose de plus au sujet, sinon, c'est redondant.
Nathan Ripert

Avec socket.io 2.1.1 , j'obtiens TypeError: clients.map is not a functionet même si cela semble prometteur, je ne suis pas tout à fait sûr de ce que l'exemple ci-dessus va réaliser - j'espérais qu'il créerait automatiquement un tableau d'objets clients avec les noms d'utilisateur inclus :).
user1063287
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.