How to avoid race conditions from client disconnections? - node.js

So, what I am doing right now is creating a new client object as new connections are received, and storing them within a self managed object; on user disconnect, I am removing the object. This is the basis of what it looks like:
var socketobj = {};
io.sockets.on('connection', function(socket){
socketobj[socket.id] = socket;
socket.on('disconnect', function(data){
delete socketobj[socket.id];
});
});
I am using each of these client objects to store extra information, such as associated usernames etc. in the form of socketobj[socket.id].user = username;
The issue I am having is that a separate portion of my code will be running, and if the client disconnects just prior to the server accessing their client object, it will come up as undefined (because the object has just been deleted), and it will throw an exception.
How can I prevent this from happening? At the very minimum, how can I stop the errors from crashing my server everytime they are thrown?

Ok, I didn't know it was event based not multithreaded, here's a new answer.
Just check if the entry exists before accessing it. If it does not, it just got deleted and you can do nothing/a different thing as is appropriate.

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 client specific variable

How do I store session specific info in Socket.io?
var client={}; //is this static across all sockets (or connected clients) that are connected?
io.on('connection', function(socket){
client.connectiontime=Date.now();
});
//on another io.on('connection') for the same connected client
io.on('connection', function(socket){
store(client.connectiontime);
}
How do I use the client variable only for the operations related to the currently connected client if it is considered static?
First, each socket is given a name that can be used to refer to it, but that changes each time the same client connects so this would not be useful if it is supposed to remain after the client leaves. If your goal is to store the connection time somewhere (a database?) then you would have to get a unique identifier from the client that could be used to find them again similar to a login. You would then pass the date object into the function that handles storing that time.
You should note though, that 'connection' is only called the first time the socket connects. A connection is not the event you normally would be using for when a client does something unless they disconnects between each access of the server program.
If you are sure you want to just use the Client object, you would likely have to create a client array and use the socket id as a key to access the object later. You would then have something like
array[socket.id].connectiontime = Date.now()
var client={}; //is this static across all sockets (or connected clients) that are connected?
var clients = [];
io.on('connection', function(socket){
clients[] = {
id : socket.id
connectiontime : Date.now()
}
});
//on another io.on('connection') for the same connected client
io.on('connection', function(socket){
// Here you would search for the object by socket.id and then store
store(client.connectiontime);
}

get contents of the request object in socket.io

I am new to socket.io and I try to tell apart every client that connects to my node server.
I want to send data to just one client, not broadcast the same data to all of them. So, I have to find a unique piece of each client.
If I got it, I have to do something like
io.on('connection', function (socket) {
var origin = socket.request;
console.log("hey, so , new ws connection is > "+origin);
});
but I get [object, Object].
What are the contents of this object, so I can get something unique like an id. Also what other data this object contains that may come handy in the future?
Thanks
UPDATE
I saw the socket.id. But, everytime I refresh, the id changes. I want something to be stable, otherwise if the client refreshes for some reason, will no longer be related with the first id. Any tips?
every connect have socket.id is unique, if you use socket-io adapter you can use socket handshake info. on Browser for geting socket.id try
$(function () {
setTimeout(function () {
$("#socketId").val(socket.id);
},100);
});
if console.log you will see socket.id in future
You'd use the socket.id property to get hold of the unique identifier for the socket (client socket).
As for other data this object contains, there are plenty that are useful, but the usefulness is dependant on the application. Have a look at the following link for available properties/methods on the socket object. http://socket.io/docs/server-api/
Some very useful methods are emit, join, leave, to, in and properties include id and 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();
});

Save socket.io ID for all open tabs in browser

Can you please tell how to solve the problem of preserving the identity socket.io, for all open tabs in the browser.
Example:
I have a page open (/index, for example), I set it to connect to socket.io and get a unique session ID. But when I open the same page on another tab - ID creates another, that is, there are already two compounds with two different ID. That is right, it is logical. But, I need to send messages to these ID, simultaneously in all the tabs (including binding to user_id), and because the session ID are different - it is impossible.
If you don't want to (or can't) use some kind of session store, and want to send messages to multiple sockets with the same user_id, you can store a map with user_id as key and an array of socket as value
var socketMap = {};
And store a reference to the socket with your handshake data
io.sockets.on('connection', function (socket) {
var userId = socket.handshake.userId;
if(!socketMap[userId]) socketMap[userId] = [];
socketMap[userId].push(socket);
});
Or with some normal event data
socket.on('auth', function(data) {
var userId = data.userId;
var authToken = data.authToken;
... // verify the data...
if(!socketMap[userId]) socketMap[userId] = [];
socketMap[userId].push(socket);
});
When you want a list of socket to send message to
var sockets = socketMap['some_user_id'];
ID of the socket will be different in any cases, and should be not used to identify user in any case. It is only used to identify Socket it self.
What you are looking for is session. Ability to relate socket connection to session - is what you are looking for.
In order to do so, you need to have sessions created for new http connections as well as restore this session during handshake process of socket.io.
That way you will be able to identify that specific socket belongs to specific session.
And then user data and other stuff you keep to session. This helps in many cases - restore session on page refresh or have single session in multiple tabs as you need it.
Read this answer of how to restore socket.io session id from handshake process: http://www.danielbaulig.de/socket-ioexpress/

Resources