Socket.IO - як отримати список підключених сокетів / клієнтів?


159

Я намагаюся отримати список усіх розеток / клієнтів, які зараз підключені.

io.sockets не повертає масив, на жаль.

Я знаю, що міг би зберегти свій власний список за допомогою масиву, але не думаю, що це оптимальне рішення з двох причин:

  1. Надмірність. Socket.IO вже зберігає копію цього списку.

  2. Socket.IO надає метод встановлення довільних значень поля для клієнтів (тобто:), socket.set('nickname', 'superman')тому мені потрібно було б бути в курсі цих змін, якби я вела власний список.

Допомога?


Ви не можете просто перетворити io.sockets в масив?
мак

2
У 0.7.6 io.sockets.sockets - простий хеш-об’єкт id => socket
mak

1
Я помітив це, але він діє дивно (не схоже на стандартні об'єкти сокет). Наприклад, я спробував: pastebin.com/fxuzVckS, але він говорить, що об'єкт socket не містить методу "get".
Енді Хін

3
socketє id, io.sockets.sockets[socket]є розетка.
мак

2
Перший аргумент - errі якщо ви використовуєте сховище пам'яті, це завжди null. .get('nickname', function(err, nickname) { ... })
мак

Відповіді:


173

У Socket.IO 0.7 у вас є clientsметод на просторах імен, це повертає масив усіх підключених сокетів.

API для простору імен:

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

Для простору імен

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

Сподіваємось, що це допоможе комусь у майбутньому

ПРИМІТКА. Це рішення працює ТОЛЬКО з версією до 1,0


ОНОВЛЕНО 2020 березня 06

З версією 1.x і вище, перейдіть за цим посиланням: дізнайтеся, скільки людей перебуває в чаті в socket.io


3
Я думаю, що вони скасували метод клієнтів у 1,0 ... просто перевіряючи це на даний момент ...
marksyzm

7
Вони скинули майже все в 1,0, оскільки це повноцінне переписування. Але як 1,0 не було випущено роками. У 1.0 ви повинні використовувати connectedоб’єкт простору імен.
3rdEden

6
@ 3rdEden, що таке синтаксис використання підключеного об'єкта простору імен? var clients = io.sockets.connected();очевидно, не працює. Спасибі
Kaya Toast


TypeError: fn.bind не є функцією
Іман Мараші

101

Socket.io 1.4

Object.keys(io.sockets.sockets); дарує всі підключені розетки.

Socket.io 1.0 Що стосується socket.io 1.0, фактично прийнята відповідь більше не діє. Тому я зробив невелику функцію, яку використовую як тимчасове виправлення:

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 Nopace namespace не стає

// 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 для простору імен стає:

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

Дивіться також це пов'язане питання , в якому я надаю функцію, яка повертає розетки для даної кімнати.

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 для простору імен :

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

Для простору імен

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

Примітка. Оскільки здається, що API socket.io схильний до злому, і якесь рішення покладається на деталі реалізації, це може бути питанням відстеження самих клієнтів:

var clients = [];

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

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

3
Дякую за це. Я здивований, що вони вийняли цю функціональність.
Тайлер Скотт

1
@TylerScott Мене теж, особливо враховуючи, що це не вказано в їхньому посібнику з міграції (якщо я щось не пропускаю). socket.io/docs/migrating-from-0-9
Nha

@nha, це не працює для мене, але повертає масив Integers, як 0, 1 і 2 і т.д., а не масив сокетів. Будь-які ідеї?
ThePixelPony

як щодо декількох вузлів? тому що я використовую кілька вузлів з магазином redis
Джон Нгуен

3
@nha ви відповідаєте точно, але це не працює для декількох вузлів з сервером redis store. з 1 вузлового процесу, ви не можете перевірити підключення сокета чи не, використовуючи ns.connected [id]
Джон Нгуен

46

Після socket.io 1.0 ми не можемо використовувати

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

більше. Натомість ви можете використовувати наступне

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
я var clients_in_the_room = io.sockets.adapter.rooms[roomId].sockets
переходжу

37

Використання Socket.IO 1.x:

Отримати масив підключених клієнтів:

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

Отримайте кількість підключених клієнтів:

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

32

Дуже просто в socket.io 1.3:

io.sockets.sockets- це масив, що містить підключені об'єкти сокета. Якщо ви зберегли ім'я користувача у кожному сокеті, ви можете:

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

Бум. У вас є імена всіх підключених користувачів.


2
Дякую! +1 для простоти. Чи знаєте ви, чи є різниця між цим методом і, скажімо, відповіддю Джозефа Дикстри? (Object.keys(io.engine.clients)
Велосипедист Лінгвіст

4
Це не працює на v1.4.5. Ще працюю над рішенням
Нуно Фуртадо

ти знайшов це? \
ocram

2
TypeError: io.sockets.sockets.map не є функцією
Király István

23

Я сьогодні пережив цей біль. Socket.io буде набагато кращим, якщо вони зможуть скласти належну документацію для свого API.

У будь-якому випадку я спробував заглянути в io.sockets і знайшов ряд варіантів, якими ми можемо скористатися:

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

Також зауважте, що при використанні socket.io з простором імен вищезазначені методи порушаться, оскільки io.sockets стає масивом замість об'єкта. Щоб вирішити проблему, просто замініть io.sockets на io (тобто io.sockets.connected стає io.connected, io.sockets.adapter.rooms стає io.adapter.rooms ...)

Тестовано на socket.io 1.3.5


1
@ Зелёный Він буде працювати, якщо ви не використовуєте простір імен. Якщо ви використовуєте простір імен, перейдіть на io.server.eio.clientsCount
Thanh Nguyen

2
Так, офіційну документацію можна було настільки покращити
CodeAndCats

18

Версія +2.0

У версії +2.0 ви вказуєте простір імен / кімнату / вузол, до якого запитуєте.

Як і у випадку мовлення, за замовчуванням - це всі клієнти з простору імен за замовчуванням ('/'):

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

Отримує список ідентифікаторів клієнта, підключених до конкретного простору імен (у всіх вузлах, якщо це можливо).

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

Приклад отримання всіх клієнтів у кімнаті простору імен:

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

Це з офіційної документації: Socket.IO Server-API


1
чи є спосіб перегляду всіх об'єктів сокета ? Наприклад, якщо я додаю socket.usernameвластивість до кожного сокета при підключенні, чи є спосіб я переглядати всі ці об'єкти сокетів (включаючи власні властивості, які я додаю до кожного сокета)? (Для довідки, я зараз використовую глобальну змінну об'єкта для зберігання додаткової інформації про сокет, коли клієнт підключається - тому не запитуючи, як це налаштувати - просто цікавить, чи є спосіб перегляду всіх об'єктів сокета за допомогою "за замовчуванням") .
користувач1063287

1
хмм, за цей відповідь , я думаю , що ви можете бачити всі підключені розетки з console.log(io.sockets.connected)- це , здається, об'єкт , де кожне значення властивості є «сокет об'єкт» , який містить ці властивості nsp, server, adaptor, id(рядок), client, conn, rooms, acks, connected, disconnected, handshake, fns, flags, _rooms, _events, _eventsCountі , нарешті , usernameщо є призначеним для користувача властивістю я додати до кожного роз'єму підключення.
користувач1063287

17

Я думаю, що ми можемо отримати доступ до об’єкта сокета з сервера, і ви можете призначити псевдонім і вказати його ідентифікатор сокета,

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будь ласка, прізвисько з io.sockets.sockets.


яка мета "client.on"? Чи можете ви використовувати такий код таким чином (приймаючи дані лише з 1 сокета) ?: io.sockets.sockets [sock_id] .on ('newmessage', function (data) {console.log (data)});
Яструб

9

Це найкращий спосіб отримати доступ до нього в socket.io 1.3

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


будь ласка, дозвольте мені поділитися цим прикладом, var room = io.sockets.adapter.rooms[room_id]; var connections = _.map(Object.keys(room), function(socketId){ return (io.sockets.connected[socketId].connected == true) });
Хані Альзамман

5

Для тих, хто хоче лише COUNT з підключених клієнтів, я вважаю, що це зробить:

io.sockets.manager.server.connections


Чи не кількість підключених клієнтів, перевірена. (трохи більше)
mrzmyr

5
щоб отримати точний підрахунокio.sockets.clients().length
Іво,

2
В даний час і те, io.sockets.manager.server.connectionsі io.sockets.clients().lengthне працюють. Це працювало для мене - тільки для підрахунку - io.engine.clientsCountі для списку клієнтів - io.engine.clientsCount. Оскільки він пробув таким чином понад 3 роки. Начебто надійний спосіб отримати інформацію про з'єднання. (На основі відповіді Джозефа Дикстри)
Асвін Рамакришнан

5

Socket.io 1.4.4

Зразок коду для вас.

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

Думаю, комусь допоможе цей блок коду.


4

У Socket.IO 1.4

Щоб отримати масив усіх підключених користувачів:

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

Щоб отримати кількість всіх клієнтів:

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

Я підтверджую, що це працює у версії 1.5.1 від socket.io
Sébastien

3

Станом на socket.io 1.5, зверніть увагу на зміну від indexOf, яка, як видається, знецінилася, та замінена на 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;
}

Для socket.io версії 2.0.3 працює наступний код:

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

Ви не можете собі уявити, скільки болю ви врятували
nicholaswmin

але версія socket.io ще не 1,5! Зараз це 1.4.8
leszek.hanusz

@MoleIsKing Obrigado amigo!

2

на socket.io 1.3 я це досяг у двох рядках

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

функція getConnectedList ()
{
    дозволити список = []
    
    для (нехай клієнт в io.sockets.connected)
    {
        list.push (клієнт)
    }
    
    повернення списку
}

console.log (getConnectedList ())

// повертає ['yIfhb2tw7mxgrnF6AAAA', 'qABFaNDSYknCysbgAAAB']


2

Для версії 2.3 це працює, і він отримає вам і сокет , мені здається, що socketIo змінюється занадто швидко і значною мірою з малочитабельною документацією після використання її деякий час.

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

все-таки це не вірно, так як у мене завжди це відчуття з розеткою Іо якось


1
я починаю думати, що це бібліотека сміття. єдине, що це правильно, безперешкодно передає багато типів даних (json, binary тощо), інакше вся архітектура є лайна і не масштабує більше 1 на 1 додаток для чату
Muhammad Umer

1

Я вважаю, ви можете отримати доступ до цього з власника менеджера сокета?

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

Відповідь 3rdEden не працював для мене, оскільки виникають проблеми з масивом, що повертає відключених клієнтів, що скидає кількість рахунків. Object.keys (io.manager.open) .length виявився найбільш надійним підрахунком у моєму досвіді. io.of ('/ space names'). manager.open, якщо ви використовуєте простори імен.
Уес Джонсон

1

Я бачу тут багато хороших відповідей і багато, де досить корисних, але не зовсім того, що мені було потрібно. Я використовую розетки для функції pubsub, в якій зацікавлений клієнт може прослухати будь-які зміни в заданому записі.

Моє конкретне питання полягало в тому, що одна і та ж розетка кілька разів приєднувалася до однієї кімнати. Рішенням цього було перевірити, чи розетка вже мала приміщення всередині своїх приміщень.

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

Сподіваюся, що це комусь допоможе.


Я думаю, що можна уникнути цього запитання "якщо", якщо ви змусите клієнта приєднатися до кімнати при з'єднанні сокета.
Chayemor

Звідки береться myObj? Як ти дійшов до цього значення?
Майкл Дрейпер

@MikeDraper myObject - це запис у базі даних, який виконує роль каналу. Що вирішує це, це випадок, коли ви хочете, щоб усі ваші клієнти оновлювалися кожного разу, коли відбувається зміна бази даних, наприклад, користувач оновлює своє ім'я, а всі підключені клієнти отримують оновлення. Тому я створюю номер для цього ідентифікатора екземпляра, враховуючи, що він унікальний (BSON). Це дуже специфічне значення для мого використання, тому мені шкода, якщо я викликав плутанину. Повідомте мене, якщо вам потрібна допомога :)
Gus Ortiz

@JMR через характер мого додатка траплялось, що сокет не раз підписувався, тому мені довелося додати цей чек.
Gus Ortiz

1

Це найпростіший спосіб у Socket.IO 1.0+, якщо ви не використовуєте просторів імен чи кімнат.

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

Це розглядає простір імен за замовчуванням і визначає довжину масиву сокетів, не потребуючи використання Object.keys()


1

З версії 1.5.1 я можу отримати доступ до всіх сокетів у просторі імен за допомогою:

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

Чомусь вони використовують звичайний об’єкт замість масиву для зберігання ідентифікаторів сокета.


Цей працює. Порожній рядок у io.of ('') працює без просторів імен.
Király István

@ KirályIstván Я не розглядав це вже деякий час, але думаю, що ви можете повністю зняти of()прикутий дзвінок у такому випадку.
rppc

1

Для кластерного режиму, використовуючи адаптер redis

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

});

Оскільки кожна розетка сама по собі є кімнатами, то можна встановити, чи існує розетка, використовуючи ту саму.


0

Ось швидкий спосіб перетворити хеш підключених сокетів з простору імен в масив за допомогою генераторів ES6 (стосується 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

Я не знаю, чи все ще йде. Але щось подібне до цього я і в кінцевому підсумку користувався (я зберігаю об’єкт сеансу у кожному підключеному сокеті, який, у свою чергу, містить ім'я користувача та іншу інформацію:

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

0

Якщо проект має кластер socket.io, це означає, що використовується адаптер socket.io-redis .

У випадку, як описано вище, отримання методу ідентифікації всіх підключених сокетів необхідно застосувати через адаптер socket.io-redis . Наведені нижче приклади можуть бути використані для цього;

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

Для більш детальної інформації відвідайте сторінку socket.io-redis github .


0

socket.io@1.7.3

Я використовував Object.Keys для підключення масиву сокета. Потім в тому ж масиві перейдіть з функцією map для побудови нового масиву об'єктів

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

Можливо, ця відповідь може допомогти отримати масив id / ім'я користувача socket.


1
Привіт - ви можете пояснити англійською мовою, як це вирішує проблему? Таким чином, це не буде лише відповіддю лише до коду. Дякую!
Макс фон Гіппель

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
Було б добре, якби ви могли додати якийсь контекст, чому "Це найкращий спосіб" і як ваша відповідь додає що-небудь до всіх багатьох відповідей вище. Код - це щось, але відповідь також повинна мати певне пояснення. Як бачите, існує багато інших відповідей на це питання. Ваша відповідь має принести щось більше до теми, інакше це зайве.
Натан Ріперт

З socket.io 2.1.1 , я отримую, TypeError: clients.map is not a functionі хоча це виглядає багатообіцяюче, я не зовсім впевнений, чого досягне вищевказаний приклад - я сподівався, що це автоматично створить масив клієнтських об’єктів із включеними іменами користувачів :).
користувач1063287
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.