I'm trying to learn Socket.io by building a set of dynamically created chatrooms that emit 'connected' and 'disconnected' messages when users enter and leave. After looking at a couple of questions I've put together something functional but most of the response linked are from people who admit they've hacked together answers and I've noticed there's a more general - and recent - discussion about the right way to do this on the Socket.io repo (notably here and here)
As I'm such a novice I don't know if the work below is an acceptable way to do things or it just happens to incidentally function but will cause performance issues or result in too many listeners. If there's an ideal - and official - way to join and leave rooms that feels less clunky than this I'd love to learn about it.
Client
var roomId = ChatRoomData._id // comes from a factory
function init() {
// Make sure the Socket is connected
if (!Socket.socket) {
Socket.connect();
}
// Sends roomId to server
Socket.on('connect', function() {
Socket.emit('room', roomId);
});
// Remove the event listener when the controller instance is destroyed
$scope.$on('$destroy', function () {
Socket.removeListener('connect');
});
}
init();
Server
io.sockets.once('connection', function(socket){
socket.on('room', function(room){ // take room variable from client side
socket.join(room) // and join it
io.sockets.in(room).emit('message', { // Emits a status message to the connect room when a socket client is connected
type: 'status',
text: 'Is now connected',
created: Date.now(),
username: socket.request.user.username
});
socket.on('disconnect', function () { // Emits a status message to the connected room when a socket client is disconnected
io.sockets.in(room).emit({
type: 'status',
text: 'disconnected',
created: Date.now(),
username: socket.request.user.username
});
})
});
Socket.IO : recently released v2.0.3
Regarding joining / leaving rooms [read the docs.]
To join a room is as simple as socket.join('roomName')
//:JOIN:Client Supplied Room
socket.on('subscribe',function(room){
try{
console.log('[socket]','join room :',room)
socket.join(room);
socket.to(room).emit('user joined', socket.id);
}catch(e){
console.log('[error]','join room :',e);
socket.emit('error','couldnt perform requested action');
}
})
and to leave a room, simple as socket.leave('roomName'); :
//:LEAVE:Client Supplied Room
socket.on('unsubscribe',function(room){
try{
console.log('[socket]','leave room :', room);
socket.leave(room);
socket.to(room).emit('user left', socket.id);
}catch(e){
console.log('[error]','leave room :', e);
socket.emit('error','couldnt perform requested action');
}
})
Informing the room that a room user is disconnecting
Not able to get the list of rooms the client is currently in on disconnect event
Has been fixed (Add a 'disconnecting' event to access to socket.rooms upon disconnection)
socket.on('disconnect', function(){(
/*
socket.rooms is empty here
leaveAll() has already been called
*/
});
socket.on('disconnecting', function(){
// socket.rooms should isn't empty here
var rooms = socket.rooms.slice();
/*
here you can iterate over the rooms and emit to each
of those rooms where the disconnecting user was.
*/
});
Now to send to a specific room :
// sending to all clients in 'roomName' room except sender
socket.to('roomName').emit('event', 'content');
Socket.IO Emit Cheatsheet
This is how I inform users of a "disconnecting user"
socket.on('disconnecting', function(){
console.log("disconnecting.. ", socket.id)
notifyFriendOfDisconnect(socket)
});
function notifyFriendOfDisconnect(socket){
var rooms = Object.keys(socket.rooms);
rooms.forEach(function(room){
socket.to(room).emit('connection left', socket.id + ' has left');
});
}
Here is a working method.
I am using socketio "socket.io": "^2.3.0" on server side. On Client side is android
// SocketIO
implementation('io.socket:socket.io-client:1.0.0') {
// excluding org.json which is provided by Android
exclude group: 'org.json', module: 'json'
}
Following is the code that is working for me.
// Join Chat Room
socket.on('ic_join', function(data) {
// Json Parse String To Access Child Elements
let messageJson = JSON.parse(data)
let room1 = messageJson.room1
console.log('======Joined Room========== ')
console.log(room1)
socket.join(room1, function(err) {
console.log(io.sockets.adapter.rooms[room1].length);
console.log(err)
})
})
// Leave Chat Room
socket.on('ic_leave', function(data) {
// Json Parse String To Access Child Elements
let messageJson = JSON.parse(data)
let room1 = messageJson.room1
console.log('======Left Room========== ')
console.log(room1)
socket.leave(room1, function(err) {
if (typeof io.sockets.adapter.rooms[room1] !== 'undefined' && io.sockets.adapter.rooms[room1] != null) {
console.log(io.sockets.adapter.rooms[room1].length);
console.log(err)
} else{
console.log("room is deleted")
}
})
})
For anyone reading this beyond 2/1/2021, using socket.io 3.1.0 and hopefully later, you can reference my example. I have found that the example on how to do this in socket.io's documentation is incorrect. They claim that in the disconnect event that socket.rooms is an object. While is uses the block container and is comma separated, there are no key pairs, meaning their demonstration of const rooms = Object.keys(socket.rooms) returns an empty value. It's creating an array out of an object that is really just an array. To my knowledge {} can only be used for block statements and objects. By some quirk, NodeJS is treating it like a normal array. I assign custom, 4 digit rooms on each connect event. So I have on the disconnect event I have the server skim through all the rooms, and if it encounters a room name with a length of 4, it tells everyone in the room that the size of the room decreased by one. On the client side, I have a socket event listener monitoring for this and when it's detected, updates a innerHTML property so that the clients can display the number of connected users.
//client side code:
socket.on('roomSize', (roomSize) => {
document.getElementById('clientCount').innerHTML = roomSize + ' clients connected';
});
//Server side code:
io.on("connection", (socket) => {
socket.on('createRoom', () => {
let ID = makeID(4)
while (io.sockets.adapter.rooms.has(ID)) {
ID = makeID(4)
}
socket.join(ID);
socket.emit('setID', ID);
});
socket.on("joinRoom", (room) => {
socket.join(room);
let roomSize = io.sockets.adapter.rooms.get(room).size
io.in(room).emit('roomSize', roomSize);
socket.emit('roomJoined', room, roomSize);
});
socket.on('disconnecting', function() {
let rooms = socket.rooms;
rooms.forEach(function(room) {
if (room.length === 4) {
let roomSize = io.sockets.adapter.rooms.get(room).size - 1
io.in(room).emit('roomSize', roomSize);
}
});
});
function makeID(length) {
var result = '';
var characters = '0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
})
I'm using Heroku + RedisToGo + Express 4.0 + socket.io 1.0.6.
I just recently upgraded to 1.0 from 0.9, and it's half working now. I've hacked together a app from tutorials but my lack of understanding socket.io is showing, so I'm taking a step back. The first question I have is that now socket.on('connect') is happening repeatedly, without stop, even when a connection is successful. My client-side console.log just keeps going and going. Here's client-side:
// Connect the user
socket.on('connect', function(){
var currentUserId = '<%= currentUser.id %>';
// Add user to redis
socket.emit('login', { userID: currentUserId});
// Retrieve presence info
socket.emit('presence');
});
// Show Presence
socket.on('presence', function(data) {
var userID = data.user;
var presence = data.presence;
if (presence) {
$('#red-dot-' + userID).css("display", "none");
$('#green-dot-' + userID).css("display", "inline");
// Show the hangout button
$('#hangout-' + userID).show();
$('#hangout-unavail-' + userID).hide();
}
else {
$('#red-dot-' + userID).css("display", "inline");
$('#green-dot-' + userID).css("display", "none");
}
});
And server-side:
io.sockets.on('connection', function (socket) {
var savedUserID;
socket.on('login', function(data){
var userID = data.userID;
savedUserID = userID;
// add first user
redis.sadd("users", userID);
redis.hmset("users:"+userID, "socketID", socket.id, "userID", userID);
});
socket.on('presence', function(){
// Get the list of online users and show Presence
redis.smembers("users", function(err,results) {
var onlineUsers = results;
for (var i in onlineUsers) {
var userID = redis.hget("users:"+onlineUsers[i],"userID", function(err,reply) {
var userID = reply;
// Emit presence
io.sockets.emit('presence', {
user: userID,
presence: "true"
});
});
}
});
});
As you can see I'm manually adding users to redis.
I found the answer in this Google Group thread.
The problem occurred because I had socket.emit('presence'); in my socket.on('connect', function(){}); client-side.
This in turn called socket.on('presence', function(){}); server-side, which was the problem.
i'm using in socket.io to get live updates from database.
here is my code:
var q = "SELECT * FROM notifications";
db.query(q, function(err, rows, fields) {
if(rows[0]) {
io.sockets.emit('newNotifications', rows[0]);
}
});
its work, but i want to add WHERE userid = "+myuserid+"
the question is how to do this?
i tried to do this with this code:
socket.on('connect', function () {
socket.send({"myuserid":"1"});
console.log('connected');
});
thanks.
You basically need to tie a userid to a particular a particular socket. How you do this is dependent on how you're handling authentication.
Once you have a userid attached to the socket, you have a couple options for getting them individual notifications. The most straightforward is to do as you wanted above. Create a query with a condition limiting the results. You need to do this on a per-socket basis though, so you'll need something like the following.
data.watchForNotification = function(userId, fn) {
// Please sanitize this and make sure you're not vulnerable to sql injection attacks
var q = "SELECT ... WHERE UserId = " + userId;
data.watchedUsers[userId] = setInterval(function() {
db.query(q, function(err, rows, fields) {
if(rows.[0]) {
fn(rows[0]);
}
});
}, 10000);
}
data.stopWatching(userId) {
if(data.watchedUsers[userId]) {
clearInterval(data.watchedUsers[userId]);
delete data.watchedUsers[userId];
}
}
io.on('connection', function(socket) {
// authenticate and set socket.userId
data.watchForNotifications(socket.userId, function(notification) {
socket.emit('notification', notification);
});
socket.on('disconnect', function() {
data.stopWatching(socket.userId);
});
});
This will setup an interval that checks every 10 seconds for new notifications and will send those to the connected socket when they come in. It will also stop the database queries for that user if they disconnect. There is a lot of pseudo code and abstraction work going on here, but it should be enough to get you where you want to go.
I am trying to build a live chat, I am using mongodb and socket.io to store the messages and users.
When a new user is created that user is stored in the mongodb and in the socket object.
If a user refreshes the page the user is removed from the socket object, meaning now in order for that person to get back in they have to create a new username and that generates a new socket.
Here is what my server side code looks like
/*
|--------------------------------------------------------------------------
| Live socket communication with front end:
|--------------------------------------------------------------------------
|
|
*/
var users = {};
io.sockets.on('connection', function (socket) {
// Listen to a new user then emit the user to all clients
socket.on('new user', function (data) {
// Check mongodb to see if the user exists and emit proper message
models.Message.findOne({username:data},function(err,user){
if(err){
console.log('something went wrong')
}
else if(user){
socket.emit('username taken', 'something');
}
else{
socket.emit('create user', data);
socket.userName = data;
socket.connected = true;
users[socket.userName] = socket;
io.sockets.emit('user name', Object.keys(users));
}
});
});
socket.on('facebook id', function(data) {
models.User.findOne({username:data.name}, function(err, user) {
if (user) {
console.log('User already exists');
socket.userName = data.name;
socket.facebook_id = data.id;
socket.connected = true;
users[socket.userName] = socket;
io.sockets.emit('user name', Object.keys(users));
}
else {
var newUser = new models.User({
username: data.name,
facebook_id: data.id
});
newUser.save(function(err, user) {
console.log('successfully inserted user/user: ' + user._id);
});
}
});
});
// Listen to a new message then emit the message to all clients
socket.on('send message', function (data, callback) {
io.sockets.emit('new message', {message: data, username: socket.userName, facebook_id: socket.facebook_id});
});
// Logic when client disconnects
socket.on('disconnect', function (data) {
if(!socket.userName) return;
seeder.disconnect(socket.userName);
delete users[socket.userName]
io.sockets.emit('user disconnected', Object.keys(users));
});
});
You see in my disconnect I remove the socket from the users object.
My question would be is there a way to save the socket info on disconnect then if the same socket tries to connect have it recognize the user and continue?
Additonal: I am thinking maybe I need to focus on creating a user login with mongodb first, then using that log in session data and pass that to the socket, creating a socket object with current database details? Does that sound like something that makes more sense, is that possible?
You can use cookies to identify users. Generate a random hash, put it in cookies, and thus this data will be transferred when establishing connection between client and server.
The client code may look like:
function generateHash(len) {
var symbols = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
var hash = '';
for (var i = 0; i < len; i++) {
var symIndex = Math.floor(Math.random() * symbols.length);
hash += symbols.charAt(symIndex);
}
return hash;
}
if (!/\buser_id=/.test(document.cookie)) { //if no 'user_id' in cookies
document.cookie = 'user_id=' + generateHash(32); //add cookie 'user_id'
}
//here goes establishing connection to server via `io.connect`
On the server-side you can write:
io.sockets.on('connection', function (socket) {
var cookie = socket.handshake.headers.cookie;
var match = cookie.match(/\buser_id=([a-zA-Z0-9]{32})/); //parse cookie header
var userId = match ? match[1] : null;
//...
Thus you have userId variable which is unique for each user. Then you can comment this line:
delete users[socket.userName]
because you should keep the user data.
You may now store your users object with userId (not username) as a key, and on each connection check whether users[userId] != null. And if such user exists, use their socket info
I'm trying to get a list of all the sockets/clients that are currently connected.
io.sockets does not return an array, unfortunately.
I know I could keep my own list using an array, but I don't think this is an optimal solution for two reasons:
Redundancy. Socket.IO already keeps a copy of this list.
Socket.IO provides method to set arbitrary field values for clients (i.e: socket.set('nickname', 'superman')), so I'd need to keep up with these changes if I were to maintain my own list.
What should I do?
In Socket.IO 0.7 you have a clients method on the namespaces. This returns an array of all connected sockets.
API for no namespace:
var clients = io.sockets.clients();
var clients = io.sockets.clients('room'); // all users from room `room`
For a namespace
var clients = io.of('/chat').clients();
var clients = io.of('/chat').clients('room'); // all users from room `room`
Note: This solution only works with a version prior to 1.0
From 1.x and above, please refer to getting how many people are in a chat room in socket.io.
Socket.IO 1.4
Object.keys(io.sockets.sockets); gives you all the connected sockets.
Socket.IO 1.0
As of Socket.IO 1.0, the actual accepted answer isn't valid any more.
So I made a small function that I use as a temporary fix:
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;
}
The API for no namespace becomes:
// 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');
The API for a namespace becomes:
// 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');
Also see this related question, in which I give a function that returns the sockets for a given room.
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
The API for no namespace:
var clients = io.sockets.clients();
var clients = io.sockets.clients('room'); // All users from room `room`
For a namespace
var clients = io.of('/chat').clients();
var clients = io.of('/chat').clients('room'); // All users from room `room`
Note: Since it seems the Socket.IO API is prone to breaking, and some solution rely on implementation details, it could be a matter of tracking the clients yourself:
var clients = [];
io.sockets.on('connect', function(client) {
clients.push(client);
client.on('disconnect', function() {
clients.splice(clients.indexOf(client), 1);
});
});
After Socket.IO 1.0, we cannot use
io.sockets.clients();
or
io.sockets.clients('room');
any more.
Instead you can use the following:
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
}
Using Socket.IO 1.x:
Get an array of the connected clients:
io.engine === io.eio // => true
Object.keys(io.engine.clients) // => [ 'US8AxrUrrDF_G7ZUAAAA', 'Ov2Ca24Olkhf2NHbAAAB' ]
Object.keys(io.eio.clients) // => [ 'US8AxrUrrDF_G7ZUAAAA', 'Ov2Ca24Olkhf2NHbAAAB' ]
Get the number of connected clients:
io.engine.clientsCount // => 2
io.eio.clientsCount // => 2
It is very simple in Socket.IO 1.3:
io.sockets.sockets - is an array containing the connected socket objects.
If you stored the username in each socket, you can do:
io.sockets.sockets.map(function(e) {
return e.username;
})
Boom. You have the names of all connected users.
I've gone through this pain today. Socket.IO would be much better if they could make a proper documentation for their API.
Anyway, I tried to look into io.sockets and found a number of options we can use:
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
Also, do note that when using socket.io with namespace, the above methods will break since io.sockets becomes an array instead of an object. To resolve, just replace io.sockets by io (i.e., io.sockets.connected becomes io.connected, io.sockets.adapter.rooms becomes io.adapter.rooms...)
It was tested on Socket.IO 1.3.5.
Version 2.x
In version 2.x you specify the namespace/room/node you are querying against.
As with broadcasting, the default is all clients from the default namespace ('/'):
const io = require('socket.io')();
io.clients((error, clients) => {
if (error) throw error;
console.log(clients); // => [6em3d4TJP8Et9EMNAAAA, G5p55dHhGgUnLUctAAAB]
});
Gets a list of client IDs connected to specific namespace (across all nodes if applicable).
const io = require('socket.io')();
io.of('/chat').clients((error, clients) => {
if (error) throw error;
console.log(clients); // => [PZDoMHjiu8PYfRiKAAAF, Anw2LatarvGVVXEIAAAD]
});
An example to get all clients in namespace's room:
const io = require('socket.io')();
io.of('/chat').in('general').clients((error, clients) => {
if (error) throw error;
console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
});
This is from the official documentation: Socket.IO Server-API
Update Socket.IO v4.0+ (last checked Nov 6 2022)
I've tried all of the other answers... None of them worked, except this:
The easiest way to get all the connected sockets is through:
await io.fetchSockets()
It returns an array of all connected sockets
Documentation
// Return all Socket instances
const sockets = await io.fetchSockets();
// Return all Socket instances in the "room1" room of the main namespace
const sockets = await io.in("room1").fetchSockets();
// Return all Socket instances in the "room1" room of the "admin" namespace
const sockets = await io.of("/admin").in("room1").fetchSockets();
// This also works with a single socket ID
const sockets = await io.in(theSocketId).fetchSockets();
Example usages
// With an async function
const sockets = await io.fetchSockets()
sockets.forEach(socket => {
// Do something
});
// Without an async function
io.fetchSockets()
.then((sockets) => {
sockets.forEach((socket) => {
// Do something
})
})
.catch(console.log)
I think we can access the socket object from the server, and you can assign the nickname, and point its socket id,
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");
});
});
On disconnect please remove the nickname from io.sockets.sockets.
This is the best way to access it in Socket.IO 1.3:
Object.keys(socket.adapter.rooms[room_id])
Version 4.0 and later (2021)
None of the answers worked for me. I will spare you the pain. Their API and documentation have changed greatly since 1.0 onward.
Server API: all available options
But you need to dig deeper here.
// Return all Socket instances
var clients = io.sockets;
clients.sockets.forEach(function(data, counter) {
//console.log(data); // Maps
var socketid = data.id; // Log ids
var isConnected = data.connected // true, false;
});
UPDATE 2023 - Get All Connected Users
I want to add to this answer by showing you how you can attach the userid to the socketid to create persistence if you need it to use it in a project(ie: private messaging).
client.js (client-side)
/***
*
*
* getConnectedUsers
*
*
*
*/
function getConnectedUsers(){
/**
*
*
* STEP 1
* GET
*
*
*/
//
var userID = localStorage.getItem('userid');//this typically would be the unique id from your database. Set this variable at login()
//set-username
socket.auth = { userID };
//console.log(socket.auth);
//
//get-connected-socket-users
socket.emit('get-connected-socket-users',{
userid:userID
});
}
/**
*
*
* STEP 2
* SET
* use this for instant communication
*
*/
socket.on('connected-socket-users',function(data){
//console.log(data);
var connectedUsers = JSON.stringify(data);
localStorage.setItem('connectedUsers',connectedUsers);
//console.log(localStorage.getItem('connectedUsers'));
});
server.js (server side)
/**
*
*
* GET ALL CONNECTED USERS
*
*
*/
socket.on('get-connected-socket-users',function(data){
//
//variables
var userid = data.userid;
socket.username = userid;
//console.log(io.sockets);
//console.log(userid);
/**
*
* GET ALL CONNECTED USERS
*
*/
const users = [];
var clients = io.sockets;
clients.sockets.forEach(function(data,counter){
users.push({
userSocketID: data.id,
username: data.username,
});
});
//console.log(users);
//var handle =
setInterval(function(){
socket.emit("connected-socket-users", users);
}, 3000);
// When you want to cancel it:
//clearInterval(handle);
//handle = 0; // I just do this so I know I've cleared the interval
});
For anyone that just wants a count of the connected clients, I believe this will do it:
io.sockets.manager.server.connections
In Socket.IO 1.4
To get the array of all connected users:
var allConnectedClients = Object.keys(io.sockets.connected); // This will return the array of SockeId of all the connected clients
To get the count of all clients:
var clientsCount = io.engine.clientsCount ; // This will return the count of connected clients
Socket.IO 1.4.4
Sample code for you.
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;
});
}
As of Socket.IO 1.5, note the change from indexOf which appears to de deprecated, and replaced by 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;
}
For Socket.IO version 2.0.3, the following code works:
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;
}
io.sockets.sockets.keys()
This helps me.
In Socket.IO 1.3, I've accomplished this in two lines:
var usersSocketIds = Object.keys(chat.adapter.rooms['room name']);
var usersAttending = _.map(usersSocketIds, function(socketClientId){ return chat.connected[socketClientId] })
Socket.io 1.7.3 or later:
function getConnectedList ()
{
let list = []
for (let client in io.sockets.connected)
{
list.push(client)
}
return list
}
console.log(getConnectedList())
// returns [ 'yIfhb2tw7mxgrnF6AAAA', 'qABFaNDSYknCysbgAAAB' ]
For version 2.3, this works and it will get you the socket too. It seems to me that socketIo is changing too fast and to much with to little readable documentation after using it for a while.
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);
}
});
Still this does not feel right, as I have always this feeling with Socket.IO somehow.
For cluster mode, using Redis adapter:
io.in(<room>).clients(function(err, clients) {
});
As each socket is itself a room, one can find whether a socket exist using the same.
Socket.IO 3.0
io.in('room1').sockets.sockets.forEach((socket, key) => {
console.log(socket);
})
It gets all socket instances in room1.
namespace.allSockets()
It returns a Promise<Set<SocketId>>.
io.allSockets(): All connected socket ids in the main namespace
io.in('room').allSockets(): All connected ids in the 'room'
io.of('/namespace').allSockets(): All connected ids in '/namespace' (you can also combine this with rooms)
To get a list of socket id's, you can do:
[...io.sockets.sockets].map(s => s[0]);
To get the socket object, do:
[...io.sockets.sockets].map(s => s[1]);
As of version 1.5.1, I'm able to access all the sockets in a namespace with:
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...
}
});
For some reason, they're using a plain object instead of an array to store the socket IDs.
I believe you can access this from the socket's manager property:
var handshaken = io.manager.handshaken;
var connected = io.manager.connected;
var open = io.manager.open;
var closed = io.manager.closed;
I saw a lot of good answers here and many were quite useful, but not quite what I needed. I am using sockets for a pubsub feature in which an interested client can listen to any changes in a given record.
My specific issue was that the same socket was joining the same room several times. The solution to this was to check if the socket had the room inside its rooms property already.
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");
}
This is the simplest way in Socket.IO 1.0 or later, if you are not using namespaces or rooms.
io.nsps["/"].sockets.length
This looks at the default namespace and determines the length of the sockets array, without needing to use Object.keys().
If the project has a socket.io cluster this means the socket.io-redis adapter is being used.
If the case is like the above, getting the all connected sockets id processes must be applied via the socket.io-redis adapter. The examples below might be used for this;
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);
});
Please visit socket.io-redis github page for more details.
Socket.IO 4.x
const socketsOnDefaultNamespace = io.of('/').sockets.size;
console.log("Number of clients connected: ", socketsOnDefaultNamespace);
const socketsInARoomInSomeNamespace = io
.of('/someNamespace')
.in('/someRoomname')
.fetchSockets()
.then((room) => {
console.log("clients in this room: ", room.length);
});
You can read more in the documentation.
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.