how to get number of socket connections using socket.io - node.js

Is there a way to get the number of connections in socket.io?
I want to display a message on my site that says "x users connected right now"
Basically if I did a socket.broadcast I want to count how many connections that would go to.

You can use
io.sockets.clients().length
Basically io.sockets.clients() returns Socket instances of all clients. If you're using rooms then you should better use
io.sockets.clients('room').length
because it returns socket instances of all clients in a particular room

Using this code Server site
var noOfUser=[];
socket.on('someEventFromClient',function(data){
//User name must unique
socket.username=data.username;
noOfUser.push(data.username);
//Now you can emit no of user to client are any where
console.log('NO of user:'+noOfUser.length);
});
socket.on('disconnect',function(){
for(var i=0;i<noOfUser;i++)
{
if(noOfUser[i]==socket.username)
{
noOfUser.splice(i,1);
}
//Now you can emit no of user to client are any where
console.log('NO of user:'+noOfUser.length);
}
});
Client side:
when user connect socket server emit this event
socket.emit('someEventFromCLient',{username:'someuniqueID'});

Related

send message to specific client using soocket.io while socket id changes rapidly

I'm running a chat server using node.js and socket and want to send message to specific client.I use socket.id to send the message to the defined user,like this:
io.sockets.in(user socket.id).emit('message',message)
but there is a problem:
user remains connect but socket id changes rapidly(About once per second) so i can not use socket.id.I tried socket.join(user email) to use user email instead of socket id but after socket id changes it does not work any more.
what's the best way to solve this?session-id?If yes,how?chat application for clients runs on android device.
This is my code:
io.on("connection", function(socket) {
socket.on("login", function(useremail) {
socket.join(useremail);
});
//Here i want to send message to specific user
socket.on('messagedetection', (senderNickname,messageContent,targetuser) => {
//create a message object
let message = {"message":messageContent, "senderNickname":senderNickname}
//targetuser is the email of target user,joined to the socket in login
io.sockets.in(targetuser).emit('message',message)
});
socket.on('disconnect', function() {
console.log( ' user has left ')
socket.broadcast.emit("userdisconnect"," user has left ") });
Making my comment into an answer since it was indeed the issue:
The problem to fix is the rapidly disconnecting/reconnecting clients. That is a clear sign that something in the configuration is not correct.
It could be that network infrastructure is not properly configured to allow long lasting socket.io/webSocket connections. Or, if your system is clustered, it could be caused by non-sticky load balancing.
So, each time the connection is shut-down by the network infrastructure, the client-side socket.io library tries to reconnect creating a new ID for the new connection.

Socket.io send messges to only some users in room

I want to send message in a room using socket.io but i some cases i want to skip some users in room so how can i do that.
Currently i am using below code to send message in group
io.on('connection', function (socket) {
sockets[socket.handshake.query.id]=socket;
console.log("user_connect",socket.handshake.query );
if(socket.handshake.query.user_type=="DRIVER"){
socket.join('orderPool');
}
socket.join('USER_'+socket.handshake.query.id);
socket.on('disconnect', function () {
delete sockets[socket.handshake.query.id];
console.log('user disconnected', socket.handshake.query.id);
});
});
io.sockets.in("ROOMNAME").emit("POOL_EVENT_RECIEVED", data);
One solution is to simultaneously keep another room "<room name>-selected users" with only selected users you want to send the messages. Don't add to this room the users you want to skip.
So, when you send messages to this room, users who weren't added to this room won't receive those messages.
sometimes io disconnected and try to reconnect again but I think it's not your problem.
Note that you can emit to rooms that exists in particular namespace. if you use default namespace '/' so try it:
io.of('/').in("ROOMNAME").emit("POOL_EVENT_RECIEVED", data);
also you can read socket.io emit cheatsheet: https://socket.io/docs/emit-cheatsheet/

Is there an alternate way of sending a private message with Socket.io (1.0+)?

Im working on a simple session based app shared by a session code in the URL. I decided to generate and assign a shorter user friendly unique ID for each client who connects to a socket, and the client who creates a session causes a socket.io room to be created with his ID.
I didnt realize until later that the private messaging mechanism in socket.io relied on each client being assigned to a room named by their ID. This means that because my room for a session is named after the creator's socket ID, using .to() will not message that client, but rather all of the clients now assigned to that room.
I could remedy this in ways that would require some re-design, but first I wanted to ask if there is an alternate way of sending a message to a specific client via his/her ID.
/*create an array of clients, where key is the name of user and value is its unique socket id(generated by socket only, you do not have to generate it) during connection.*/
var clients = {};
clients[data.username] = {
"socket": socket.id
};
//on server side
socket.on('private-message', function(data){
io.sockets.connected[clients[data.username].socket].emit("add- message", data);
});
//on client side
socket.emit("private-message", {
"username": userName,
"content": $(this).find("textarea").val()
});
socket.on("add-message", function(data){
notifyMe(data.content,data.username);
});

Socket.io - Emit to array of socket id

I have socket id of each connected user stored in my database. When any user posts a comment or status, I want to broadcast the same to all his/her connections using socket id stored in my database.
I can emit the message to individual client using his/her socket id by using io.sockets.connected[ socket.id ].emit('privateMsg', 'Hello! How are you?');
But how do I emit the same to the array of socket id which i have generated using select query from my database.
You can use concept of rooms. Whenever a socket connection arrives, join the connections to a room. And on disconnect, remove the socket from the room.
socket.on('connection', function () {
socket.join('room1');
});
socket.on('disconnect', function () {
socket.leave('room1');
});
Now when you want send messages to sockets connected on a room, you can broadcast it to room.
socket.broadcast.to('room1').emit('eventName', data);
You could dynamically create a room for each socket that connects and emit to it without having to loop over the entire array every time. Like so:
socketids.foreach(function(socketid){io.sockets.connected[socketid].join(sendingSocket.id);});
Then you can emit to those sockets from your sending socket by doing the following:
sendingSocket.to(sendingSocket.id).emit('publicMessage', 'Hello! How are you?')
As a side-note, I don't think keeping socket ids that change in a database is the best approach, since they have no persistence at all. You may want to try to find a better identifier for your database.
For anyone who visites this thread. After Socket.io 3.x we can pass arrays of room names and socket ids to io object. like this:-
socketIds = [xlksdf09sdfsk,sdosdifns90sdf,..........]
io.sockets.to(socketIds).emit('hello','recieving all sockets')
roomNames = [roomA,roomB]
io.to(roomNames).emit('hello','recieves each member of the rooms')
// Event is also not emmitted multiple times on the client side
// evern if single socketId is present in multiple rooms.

How can I enforce a maximum number of connections from one user with Socket.IO?

I have a very simple Socket.IO group chat system (this one). I want to prevent people from spamming new connections from their browser using JavaScript trickery. This was a problem the one time I publicized the website.
What measure should I use to prevent this? I want to count the number of connections from a browser and it it goes over a threshold, I want to drop all connections. Should I use the IP address? Is the socket.id unique to a user? How should I do it?
If you want to look at the Socket.IO code, see the highlighted code here.
I had the same issue in a multiplayer game, to prevent a user playing through more than one tabs.
There's so many ways a client can refuse to be identified, and having their way of logging in with more than one ID. But since you only want to prevent a user in the same browser it's relatively easy.
First, use passport for authentication and passport.socketio to "bridge" req.user from Express middleware to socket.request.user
Next, since io.on('connection') will always fire for the latest socket request from the client, you can use this as an opportunity to "expire" any old sockets still connected from the same client. This is where socket.request.user will come in handy to identify whether it's the same user client. Something like this:
io.on('connection', function(socket) {
var user = socket.request.user;
// Suppose this user has connected from another tab,
// then the socket.id from current tab will be
// different from [see *1]
var current_socket_id = socket.id;
var last_socket_id = user.latest_socket_id;
if (last_socket_id) {
// If the user has an existing socket connection
// from the previously opened tab,
// Send disconnection request to the previous socket
io.to(last_socket_id).emit('disconnect');
// client-side will look like
// socket.on('disconnect', function(){
// alert('You connected from a new tab, this tab will close now.')
// window.close();
// });
}
// [*1] current socket.id is stored in the user
user.latest_socket_id = socket.id;
user.save();
});

Resources