Socket.IO - como obtenho uma lista de soquetes / clientes conectados?

159

Estou tentando obter uma lista de todos os soquetes / clientes que estão conectados no momento.

io.sockets infelizmente não retorna uma matriz.

Sei que poderia manter minha própria lista usando uma matriz, mas não acho que essa seja uma solução ideal por 2 motivos:

  1. Redundância. O Socket.IO já mantém uma cópia desta lista.

  2. O Socket.IO fornece um método para definir valores de campo arbitrários para clientes (ou seja:), socket.set('nickname', 'superman')para que eu precise acompanhar essas alterações se quiser manter minha própria lista.

Socorro?

Andy Hin
fonte
Você não pode simplesmente converter io.sockets em uma matriz?
mak
2
Em 0.7.6 io.sockets.sockets é um id simples de hash objeto => tomada
mak
1
Notei isso, mas está agindo de forma estranha (não parece objetos de soquete padrão). Por exemplo, tentei: pastebin.com/fxuzVckS, mas está dizendo que o objeto socket não contém um método 'get'.
Andy Hin
3
socketé id, io.sockets.sockets[socket]é o soquete.
mak
2
O primeiro argumento é erre, se você estiver usando armazenamento de memória, é sempre null. .get('nickname', function(err, nickname) { ... })
mak

Respostas:

173

No Socket.IO 0.7, você tem um clientsmétodo nos espaços para nome, isso retorna uma matriz de todos os soquetes conectados.

API para nenhum espaço de nome:

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

Para um espaço para nome

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

Espera que isso ajude alguém no futuro

NOTA: Esta solução funciona com a versão anterior à 1.0


ATUALIZAÇÃO 2020 Mar 06

A partir da 1.xe acima, consulte este link: obter quantas pessoas estão em uma sala de bate-papo no socket.io

3rdEden
fonte
3
Eu acho que eles caiu o método de clientes em 1,0 ... apenas verificando que fora no momento ...
marksyzm
7
Eles lançaram quase tudo na versão 1.0, pois é uma reescrita completa. Mas como 1.0 não foi lançado há anos. Na 1.0, você precisa usar o connectedobjeto do espaço para nome.
precisa saber é o seguinte
6
@ 3rdEden, qual é a sintaxe para usar o objeto conectado do espaço para nome? var clients = io.sockets.connected();obviamente não funciona. Obrigado
Kaya Toast
5
A partir da 1.xe acima: stackoverflow.com/questions/9352549/…
Musa Haidari
TypeError: fn.bind não é uma função
Iman Marashi
101

Socket.io 1.4

Object.keys(io.sockets.sockets); fornece todos os soquetes conectados.

Socket.io 1.0 A partir do socket.io 1.0, a resposta realmente aceita não é mais válida. Então, eu criei uma pequena função que eu uso como uma correção temporária:

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

A API para No namespace se torna

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

A API para um espaço de nome se torna:

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

Veja também esta questão relacionada , na qual dou uma função que retorna os soquetes para uma determinada sala.

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 nenhum espaço de nome :

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

Para um espaço para nome

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

Nota: Como parece que a API socket.io está sujeita a falhas, e algumas soluções dependem de detalhes de implementação, pode ser uma questão de rastrear os clientes:

var clients = [];

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

    client.on('disconnect', function() {
        clients.splice(clients.indexOf(client), 1);
    });
});
nha
fonte
3
Obrigado por isso. Estou surpreso que eles tiraram essa funcionalidade.
Tyler Scott
1
@TylerScott Eu também, especialmente porque isso não é abordado no guia de migração (a menos que esteja faltando alguma coisa). socket.io/docs/migrating-from-0-9
nha
@ nha, isso não funciona para mim, mas retorna uma matriz de números inteiros, como 0, 1 e 2 etc, em vez de uma matriz de soquetes. Alguma ideia?
ThePixelPony
que tal para vários nós? porque eu usando vários nós com redis store
John Nguyen
3
@ você responde é exatamente, mas não está funcionando para vários nós com o servidor de armazenamento redis. a partir de 1 processo de nó, você pode não verificar soquete conectado ou não por usando ns.connected [id]
John Nguyen
46

Após o socket.io 1.0, não podemos usar

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

não mais. Em vez disso, você pode usar o seguinte

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
fonte
3
eu mudo paravar clients_in_the_room = io.sockets.adapter.rooms[roomId].sockets
Fábio Zangirolami
37

Usando o Socket.IO 1.x:

Obtenha a matriz dos clientes conectados:

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

Obtenha o número de clientes conectados:

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

Muito simples no socket.io 1.3:

io.sockets.sockets- é uma matriz que contém os objetos de soquete conectados. Se você armazenou o nome de usuário em cada soquete, poderá:

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

Estrondo. Você tem os nomes de todos os usuários conectados.

or29544
fonte
2
Obrigado! +1 por simplicidade. Você sabe se existe alguma diferença entre esse método e, por exemplo, a resposta de Joseph Dykstra? (Object.keys(io.engine.clients)
cyclingLinguist
4
Isso não funciona na v1.4.5. Ainda trabalhando em uma solução
Nuno Furtado
você encontrou? \
ocram
2
TypeError: io.sockets.sockets.map não é uma função #
Király István
23

Eu passei por essa dor hoje. O Socket.io será muito melhor se eles puderem criar uma documentação adequada para sua API.

Enfim, tentei examinar o io.sockets e encontrei várias opções 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

Além disso, observe que, ao usar o socket.io com espaço para nome, os métodos acima serão interrompidos, pois io.sockets se torna uma matriz em vez de um objeto. Para resolver, basta substituir io.sockets por io (ou seja, io.sockets.connected se torna io.connected, io.sockets.adapter.rooms se torna io.adapter.rooms ...)

Testado em socket.io 1.3.5

Thanh Nguyen
fonte
1
@ Itелёный Funcionará se você não estiver usando espaço para nome. Se você estiver usando espaço para nome, altere para io.server.eio.clientsCount
Thanh Nguyen
2
Sim, a documentação oficial poderia ser muito melhorada.
CodeAndCats 1/16/16
18

Versão +2.0

Na versão +2.0, você especifica o espaço para nome / sala / nó no qual está consultando.

Como na transmissão, o padrão são todos os clientes do espaço para nome padrão ('/'):

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

Obtém uma lista de IDs de clientes conectados a um namespace específico (em todos os nós, se aplicável).

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

Um exemplo para obter todos os clientes na sala de namespace:

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

Isto é da documentação oficial: Socket.IO Server-API

John Galt
fonte
1
existe uma maneira de visualizar todos os objetos de soquete ? por exemplo, se eu adicionar uma socket.usernamepropriedade a cada soquete na conexão, há uma maneira de exibir todos esses objetos de soquete (incluindo as propriedades personalizadas adicionadas a cada soquete)? (para referência, atualmente estou usando uma variável de objeto global para armazenar informações adicionais de soquete quando um cliente se conecta - portanto, não perguntando como configurá-las - apenas interessado em saber se existe uma maneira de exibir todos os objetos de soquete por 'padrão') .
user1063287
1
hmm, por esta resposta , eu acho que você pode ver todos os soquetes conectados com console.log(io.sockets.connected)- parece ser um objeto, onde cada valor de propriedade é um "objeto socket" que contém essas propriedades nsp, server, adaptor, id(a string), client, conn, rooms, acks, connected, disconnected, handshake, fns, flags, _rooms, _events, _eventsCounte, finalmente, usernameo que é a propriedade costume adicionar a cada tomada na conexão.
user1063287
17

Acho que podemos acessar o objeto de soquete do servidor, e você pode atribuir o apelido e apontar seu ID de soquete,

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

Em disconnect, remova o apelido de io.sockets.sockets.

sunil n jose
fonte
qual é o objetivo de 'client.on'? Você pode usar seu código assim (aceitando apenas dados de 1 soquete) ?: io.sockets.sockets [sock_id] .on ('newmessage', function (data) {console.log (data)});
The Hawk
9

Esta é a melhor maneira de acessá-lo no socket.io 1.3

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

ksloan
fonte
por favor, deixe-me compartilhar este exemplo, 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 17/11/2015
5

Para qualquer pessoa que queira apenas uma CONTAGEM de clientes conectados, acredito que isso será possível:

io.sockets.manager.server.connections

crickeys
fonte
os clientes conectados não são contados, testados. (bit more)
mrzmyr 16/03/12
5
para obter um uso preciso da contagemio.sockets.clients().length
Ivo
2
Atualmente ambos io.sockets.manager.server.connectionse io.sockets.clients().lengthnão trabalham. Isso funcionou para mim - apenas para contagem - io.engine.clientsCounte para a lista de clientes - io.engine.clientsCount. Desde que permaneceu assim por mais de 3 anos. Parece uma maneira confiável de obter as informações de conexão. (Baseado na resposta de Joseph Dykstra)
Aswin Ramakrishnan
5

Socket.io 1.4.4

Código de exemplo para você.

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

Eu acho que vai ajudar alguém nesse bloco de código.

Tiago Zamperini
fonte
4

No Socket.IO 1.4

Para obter a matriz de Todos os usuários conectados:

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

Para obter a contagem de todos os clientes:

var clientsCount = io.engine.clientsCount ; // This will return the count of connected clients
KIA
fonte
Confirmo que isso funciona na versão 1.5.1 do socket.io
Sébastien
3

No socket.io 1.5, observe a alteração de indexOf que parece depreciada e substituída 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 versão 2.0.3, o seguinte código funciona:

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
fonte
você não pode imaginar quanta dor que você me salvou
nicholaswmin
mas a versão socket.io ainda não é 1.5! Agora é 1.4.8
leszek.hanusz
@MoleIsKing Obrigado amigo!
2

no socket.io 1.3 eu consegui isso em 2 linhas

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

Socket.io 1.7.3 (+):

função getConnectedList ()
{
    deixe lista = []
    
    for (deixe o cliente em io.sockets.connected)
    {
        list.push (cliente)
    }
    
    lista de retorno
}

console.log (getConnectedList ())

// retorna ['yIfhb2tw7mxgrnF6AAAA', 'qABFaNDSYknCysbgAAAB']

Alexandre Daubricourt
fonte
2

Para a versão 2.3, isso funciona e você também recebe o soquete , parece-me que o socketIo está mudando muito rápido e muito com pouca documentação legível depois de usá-lo por um tempo.

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

ainda assim isso não parece certo, pois sempre tenho esse sentimento com o soquete Io

Joris Ceelen
fonte
1
estou começando a pensar que é uma biblioteca de lixo. única coisa que faz a direita perfeitamente transferir muitos tipos de dados (JSON, binário, etc) arquitetura de outra forma todo é uma porcaria e não escala além 1 no aplicativo 1 bate-papo
Muhammad Umer
1

Eu acredito que você pode acessar isso a partir da propriedade do gerenciador do soquete?

var handshaken = io.manager.handshaken;
var connected = io.manager.connected;
var open = io.manager.open;
var closed = io.manager.closed;
Dan Steele
fonte
A resposta da 3rdEden não funcionou para mim, pois há problemas com a matriz retornando clientes desconectados, o que diminui a contagem. Object.keys (io.manager.open) .length acabou sendo a contagem mais confiável em minha experiência. io.of ('/ namespace'). manager.open se você estiver usando namespaces.
Wes Johnson
1

Eu vejo muitas respostas boas aqui e muitas onde são úteis, mas não exatamente o que eu precisava. Estou usando soquetes para um recurso de pubsub no qual um cliente interessado pode ouvir as alterações em um determinado registro.

Meu problema específico era que o mesmo soquete estava entrando na mesma sala várias vezes. A solução para isso foi verificar se o soquete já tinha o quarto dentro da propriedade de seus quartos.

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 isso ajude alguém.

Gus Ortiz
fonte
Eu acho que é possível evitar essa declaração 'if', se você fizer o cliente entrar na sala após a conexão do soquete.
Chayemor 25/11/2015
De onde vem o myObj? Como você chegou a esse valor?
Michael Draper
@MikeDraper myObject é o registro em um banco de dados que atua como um canal. O que isso resolve é o caso em que você deseja que todos os seus clientes sejam atualizados sempre que ocorrer uma alteração no banco de dados, por exemplo, um usuário atualiza seu nome e todos os clientes conectados recebem uma atualização. Portanto, crio uma sala para esse ID de instância, uma vez que é único (BSON). É um valor muito específico para o meu caso de uso, então, desculpe-me por ter causado alguma confusão. Deixe-me saber se você precisar de ajuda :)
Gus Ortiz
@JMR devido à natureza do meu aplicativo, aconteceu que um soquete foi assinado mais de uma vez, por isso tive que adicionar essa verificação.
Gus Ortiz
1

Essa é a maneira mais simples do Socket.IO 1.0+, se você não estiver usando espaços ou espaços para nome.

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

Isso examina o espaço para nome padrão e determina o comprimento da matriz de soquetes, sem a necessidade de usar Object.keys()

suncannon
fonte
1

A partir da versão 1.5.1, eu posso acessar todos os soquetes em um espaço para nome com:

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 alguma razão, eles estão usando um objeto simples em vez de uma matriz para armazenar os IDs de soquete.

rppc
fonte
Este aqui funciona. Uma cadeia vazia em io.of ('') funciona sem espaços para nome.
Király István
@ KirályIstván Não analiso isso há um tempo, mas acho que você pode remover completamente a of()chamada em cadeia nesse caso.
Rppc
1

Para o modo de cluster, usando o adaptador redis

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

});

Como cada soquete é uma sala, é possível descobrir se existe um soquete usando o mesmo.

Anuj Nautiyal
fonte
0

Aqui está uma maneira rápida de converter o hash de soquetes conectados de um espaço para nome em uma matriz usando geradores ES6 (aplica-se 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
fonte
0

Não sei se isso ainda está acontecendo. Mas algo assim foi o que acabei usando (mantenho um objeto de sessão em cada soquete conectado, que por sua vez contém o nome de usuário e outras informações:

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

Se o projeto tiver um cluster socket.io, isso significa que o adaptador socket.io-redis está sendo usado.

Se o caso for o anterior, é necessário aplicar o processo de identificação de todos os soquetes conectados por meio do adaptador socket.io-redis . Os exemplos abaixo podem ser usados ​​para isso;

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 a página do socket.io-redis no github para obter mais detalhes.

efkan
fonte
0

[email protected]

Eu usei Object.Keys para obter a matriz do soquete conectada. Na mesma matriz, itere a função map para criar uma nova 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);

Talvez esta resposta possa ajudar a obter o array socket id / username.

jvaldezb
fonte
1
Oi - você pode explicar em inglês como isso resolve o problema? Dessa forma, não será apenas uma resposta apenas de código. Obrigado!
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.
Ark Iv
fonte
1
Seria bom se você pudesse adicionar algum contexto ao porquê 'Esta é a melhor maneira' e como sua resposta adiciona algo a todas as muitas respostas acima. Código é algo, mas uma resposta também deve ter alguma explicação. Como você pode ver, existem muitas outras respostas para essa pergunta. Sua resposta deve trazer algo mais para o assunto, caso contrário, é redundante.
Nathan Ripert
Com socket.io 2.1.1 , recebo TypeError: clients.map is not a functione, embora pareça promissor, não tenho muita certeza do que o exemplo acima alcançará - eu esperava que ele criasse automaticamente uma matriz de objetos cliente com nomes de usuário incluídos :).
user1063287