How to detect reconnect event in Socket IO - node.js

Whenever a client connects, I assign an id to that client using socket.id, and maintain it in the server for future reference. The problem I'm having right now is with disconnect/reconnect. I'm not even sure how to simulate this scenario, because if I reload the client page, it's technically creating a new client and connect to the server with different id. If I disconnect and connect the client manually then the client will again have a different id (socket.id).
I set up 'reconnect' event on both client and server using socket.on('reconnect',function(){...}), but it never seems to get called, given what I tried above.
So how would you go about simulating this scenario? And then what's the best way to detect if this new client is actually the same client that has disconnected?

There is a reconnect event on the client side inside which you can emit to the server and find the the reconnected client
socket.on('reconnect', function () {
console.log('you have been reconnected');
// where username is a global variable for the client
socket.emit('user-reconnected', username);
});
on the server you can get that as
socket.on('user-reconnected', function (username) {
console.log(username + ' just reconnected');
});

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 'disconnect event' firing too late after reconnect

I've a simple code which set offline for the user in my sql database.
Server
io.on('connection', function (socket) {
ApiHelper.setUserOnline(socket.token);
socket.on('disconnect', function () {
ApiHelper.setUserOffline(socket.token);
});
}
So lets say,
An user connect to socket than he lost the network connection then reconnect.
I get this logs.
User connected (he is online)
Network losted.
Network losted but disconnect event has not received by server yet, so user is still online
User reconnect to network and then socket. User is still online.
Previous disconnect event recevied by server and user is set offline in database. But wait user has just reconnect so actually user must be online.
Because of disconnect event fired late we saw the user is offline in database.
How can I achieve this problem?
I think the best way is to store the socket.id in the sql database, so when a user login / connects you first check if that user.account is already online or not.
If it is online, then use the old socket.id to notify that the account has been opened from another window/device/whatever and replace it in the db for the new socket.id
and by replacing the old socket.id for the new one in the db, when a disconnect occurs you will really know if it was the currently active client (socket.id) using that account or not.
So at the disconnection : check if the disconnecting socket.id is in the database or not
(in other words : currently connected or not)
io.on('connection', function (socket) {
/* check if the account associated to this socket was
previously associated to another socket.id ...
(that might be currently connected or about to disconnect (lost connection)
*/
if(thisAccountWasOnlineBefore){
socket.to(old.socket.id).emit('exit', 'account opened from another session');
}
//pass also the socket.id so you can store it in the db
ApiHelper.setUserOnline(socket.id, socket.token);
socket.on('disconnect', function () {
//check if socket.id is associated to any account in the db
// if true : remove the socket.id and set as account status : offline
});
}

Socket.io doesn't send disconnect event to NodeJS in IE8/9

I use NodeJS with socket.io for my chat application. When client refreshes/closes the window or navigates to different URL I need client to emit "disconnect" event to NodeJS server. All works nice with excpetion of IE8/9. When refresh happens "disconnect" event is not send to server so server is not aware that this particular client is no longer connected.
I managed to use:
window.onbeforeunload = function(e) {
socket.disconnect();
};
and this takes care of clicking back/forward button and then the server is informed about client disconnecting. Refreshing the page or closing the tab however doesn't send disconnect to server. It seems that refreshing the page is too quick so the socket.disconnect() has no chance of executing. It seems so as if I do alert like below, client pauses for alert window and server receives disconnect message.
window.onbeforeunload = function(e) {
socket.disconnect();
alert("hey watchout!");
};
Now, is there any way to make IE8/9 send disconnect event to NodeJS when page is refreshed?
You can send information back and forth and find the time of the last reply, compare it to now and if the difference is greater than a number, disconnect the client, then reconnect when the client starts sending again.
You can use something like:
On client:
socket.on('ping',function(){socket.emit('pong',(new Date()).getTime());});
On server:
socketReferences = new Array();
io.on('connection',function(socket){
socketReferences.push(socket);
socket.on('pong',function(data){
if(new Date()).getTime()>5000){
// disconnect code here
}
});
});
setInterval(function(){
for(socket in socketReferences)
socketReferences[socket].emit('ping','');
},700);

socket.io client connection cannot be made on the 2nd time

Currently, I am implementing an API using nodejs express, then it needs to connect to socket.io and send event.
The API is located in socket.io-client (client), and it connects to socket.io (server)
1st API call: success
The connection is made for the 1st call of the API, message is sent and socket can be disconnected, with the 'disconnect' callback is invoked both on client and server side.
2nd API call: failure
When the API is invoked the 2nd time, the connection to server cannot be made, 'client' callback on client side is not called.
3rd API call: success
Then I tried to restart the client side, keeping other things unchanged. The API is called again, and the connection to socket.io is made successfully and everything is fine.
Can anyone explain the logistics behind this?
Updated
client.js
App.getByUserId(message.to_id, function(error, app) {
var socket = io.connect('http://127.0.0.1:9002');
socket.on('connect', function(){
console.log("client connect socket id:" + socket.id);
console.log("appkey:" + app.private_token);
socket.emit('appkey.check',{appkey: app.private_token, uuid: message.to_id.uuid}, function(data){
socket.emit("forceDisconnect");
socket = null;
});
});
You just hit one of Socket.IO's many "features" or "bugs" depending how you see this. Socket.IO tries to be smart and re-use connections (which causes a lot of connection issues actually) The way around this is use the force new connection option in your io.connect:
io.connect('http://127.0.0.1:9002', { 'force new connection': true });
What you could also do is use https://github.com/primus/primus which wraps Socket.IO if you use the socket.io transformer. Internally, it completely removes the use of the io.connect and uses the much more lower level io.Socket constructor to create more stable connections that you would get with a stock socket.io.
With socket 1.0+, you have to use this for forcing new connection.
io.connect(SERVER_IP, { 'forceNew': true });

emitting data via socket on browser close /window close

I need to send data to nodejs server via socket.io when the user closes the browser tab .
I tried doing :
var data={};
window.onbeforeunload = function() {
// i have a object to be sent
data.data1='abcd';
data.data2=1234;
socket.emit("senddata",data);
}
This code works when the user navigates around clicking links on the site but doesnot work when the user closes the browser tab
I also tried configuring the socket io on server side as below .. thinking the error may be due to socket connection being closed before emitting data:
var io = require('socket.io').listen(app.listen(port));
io.configure(function () {
io.set('close timeout',12000);
});
It also didnt work most of the time.
I also tried this on client side:
var socket = require('socket.io').listen(80, {
"sync disconnect on unload":false
});
It also did not work
I had tried receiving data like this
var io = require('socket.io').listen(app.listen(port));
io.sockets.on('connection', function (socket) {
socket.on('senddata', function (data) {
// data processing
});
});
please ..help me with this problem..thanks in advance..
When user connects - register on server side the time it happened.
Socket.IO has heart beating and pinging functionality. So just subscribe to disconnect event on server side and once it happens - means client disconnected - and you have on server time when client had connection. So that way you have timespan of client session.
Do not trust client to tell you any time or important data, as client can simply 'lie' - which leads to hacks/cheats/bugs on your server-side.
There is no reliable way to send data just before disconnect from client-side at all. There is nothing in Socket.IO for that, nor in just one of transports (WebSockets). As well as there is too many different scenarios of disconnection (power off, force close, ethernet cable out, wifi lose, etc).

Resources