socket io js delay disconnect emit - javascript

socket.on('disconnect') is fired immediately on client side, but server side it will take one minute.
scenario 1:- if client is disconnect due to internet problem, server side disconnect emits after 1 minutes, any way to find immediately on server side.
i tried to change the pingTimeout= 30000 and pingInterval=12000 but every 30 seconds it reconnecting and connect.

You can use a timeout delay and the socket disconnection event to make it easier to disconnect and reconnect.
When your socket connects, add them to a bucket object.
if (socket.request.sessionID && !bucket[socket.request.sessionID]) {
bucket[socket.request.session.player.id] = socket.id; //nuuu they stealin mah bukkit
}
This adds the player's id (which I track through node session tethered into the socket) as a key to the socketId
//object for delayed log out
let disconnection = {
sid : null, //socket id
delay : null //timeout id
};
Create an object that stores your socket ID so you can track who was disconnected.
socket.on('disconnect', function () {
disconnection.sid = socket.request.sessionID; //grab session id
disconnection.delay = setTimeout(() => {
//set timeout to variable, in case of reconnection
delete bucket[socket.request.sessionID];
//emit the disconnection event
}, 60000);
});
When the user disconnects, set a timeout for however long they have to reconnect.
Upon reconnection, simply do:
io.sockets.on("connection", socket => {
//check for disconnection, compare socket ids, and remove timeout if sockets match
if (disconnection.delay && disconnection.sid == socket.request.sessionID) {
clearTimeout(disconnection.delay);
disconnection.sid = null;
}
});
This will check the reconnection for an existing socketID and clear the timeout, successfully establishing the connection once more.
Note that this code is a copy of SourceUndead (my game) so some of it might not directly translate to you (for instance, my socket variable is bound with the session as well), but the concept of a timeout disconnection is the same.

Related

Is it possible to listen to an inactivity event in socket.io?

Compared to using websockets directly, socket.io handles heartbeat events and automatic reconnection. However, as my client is very time sensitive, I also want to display a warning message when the socket has been inactive for N seconds, and remove the warning when a new message / heartbeat comes in.
Is it possible to create event listeners for such "active" / "inactive" events on socket.io? Or would it be easier to use plain websockets and implement the heartbeat / reconnection mechanism by hand?
I would suggest having a setTimeout variable in the socket that will emit a message to user in case of inactivity, and reset the timeout after receiving the message.
Something along the lines of:
io.on('connection', async (socket) => {
let userTimeout = setTimeout(() => socket.to(socket.id).emit("You have been inactive"), 60000);
/* ... */
socket.on('message', async(socket) => {
if(userTimeout) clearTimeout(userTimeout);
userTimeout = setTimeout(() => socket.to(socket.id).emit("You have been inactive"), 60000);
})
})

After the client is disconnected, how does the server know when it reconnects?

I currently have a chat.
If the client connection is unstable and the socket connection is lost, the server will recognize it as socket.disconnect and delete the client from the chat room.
Then, when reconnecting, the client automatically exits the room.
How do I resolve this?
The idea is to create a setTimeout at disconnect to hold the client for 20 seconds to be deleted from the chat room, and then delete the setTimeout when reconnecting.
When doing this, how do you know that the client is reconnected?
Does socket.id change when reconnected?
If socket.id does not change because I created a user-specific array based on socket.id, I think we can solve this problem at the moment.
socket.on('reconnect', function() {
if( typeof event_timeout[socket.id] !== "undefined" )
clearTimeout(event_timeout[socket.id]);
}
socket.on('disconnect', function() {
event_timeout[socket.id] = setTimeout( exit_chat, 20000 );
}

How can I detect disconnects on socket.io?

I am using socket.io in my project. I turned on reconnect feature. I want to if user disconnects from server show an alert (Your internet connection loss. Trying reconnect). And if the user reconnects again I want to show one more alert (Don't worry, you are connected).
How can I do it?
To detect on the client you use
// CLIENT CODE
socket.on('disconnect', function(){
// Do stuff (probably some jQuery)
});
It's the exact same code as above for a node.js server too.
If you want for some reason to detect a user disconnecting and display it to the others, you will need to use the server one to detect it the person leaving and then emit back out a message to the others using something like:
socket.on('disconnect', function(){
socket.broadcast.to(roomName).emit('user_leave', {user_name: "johnjoe123"});
});
Hope this helps
socket.io has a disconnect event, put this inside your connect block:
socket.on('disconnect', function () {
//do stuff
});
I handled this problem this way. I've made an emit sender on client which is calling heartbeat on server.
socket.on('heartbeat', function() {
// console.log('heartbeat called!');
hbeat[socket.id] = Date.now();
setTimeout(function() {
var now = Date.now();
if (now - hbeat[socket.id] > 5000) {
console.log('this socket id will be closed ' + socket.id);
if (addedUser) {
--onlineUsers;
removeFromLobby(socket.id);
try {
// this is the most important part
io.sockets.connected[socket.id].disconnect();
} catch (error) {
console.log(error)
}
}
}
now = null;
}, 6000);
});
I found this code function to call:
io.sockets.connected[socket.id].disconnect();
inpired on invicibleTrain iv made a online checker also
SERVER SIDE
const sockets={online:{},admins:{}}
// the disconnect function you create the way you wish to, example:
const disconnect=()=>{
socket.emit('disconected')
io.in(socket.id).disconnectSockets()
delete sockets.online[socket.uid]
}
io.on('connection',socket=>{
socket.emit('connection',socket.id)
// the checker if user is online
let drop
const dropCheck=()=>{
if(!socket) return; // if user connects twice before the check, simply stops process
socket.emit('dropCheck')
drop = setTimeout(()=>disconnect(),4000) // 4 secs to recieve answer
}
const setDrop=()=>setTimeout(()=>dropCheck(),60000) // 60 secs to restart the process
socket.on('dropCheck',()=>{
clearTimeout(drop) // cancells actual drop coutdown (if any)
setDrop() // sets a new
})
//sets the user ID inside the socket used for comunication
socket.on('uid',uid=>{
socket.online[uid] = {status:'busy',socket:socket.id}
setDrop()
})
})
CLIENT SIDE
const sio = io(`...httpAddress...`,{transports:['websocket']})
sio.on('connection',socket=>{
sio.emit('uid','user Id here..') // sends the the user ID: uid
sio.on('dropCheck',()=>{ // responds to the checker
sio.emit('dropCheck')
})
})
Explanation:
The user logs in and after 60 seconds dropCheck is called
the dropCheck emits a ping and set a timmer of 4 seconds
the user handle the emited ping and responds with another ping
a: if the response comes within 4 secs the 4 secs timmer is cancelled and refreshes the 60 seconds timmer (restarting the
process)
b: if the response fails or delay too much the disconnect() function is called

Nodejs, clients not always receiving server messages

I am setting up a very basic node application, the plan is that anyone can go on the site and press a letter and that will increment a counter. Everybody can then see that counter going up as people all over the world are incrementing it.
It works brilliantly, except that the way i set it up in the beginning then the node server is contacting each client 20 times per second, which is very wasteful.
So in order to avoid that i added a condition that the counter must have increased in order for the node server to send the message. But when I do that the messages never really make it to all the clients, how they go to the clients is some confusing, apparently random order.
This is my first node app and I am still getting the hang of it, can anybody point me in the right direction with this? The problem is probably in the increment_time function.
Server part:
var http=require('http');
var io=require('socket.io');
var fs=require('fs');
var sockFile=fs.readFileSync('text');
server=http.createServer();
//2. get request, via port, http://localhost:8000
server.on('request', function(req, res){
console.log('request received');
res.writeHead(200, {'content-type':'text/html'});
res.end(sockFile);
});
//have server and socket listen to port 8000.
server.listen(8000);
var socket=io.listen(server);
//the lower the number the less chatty the debug becomes.
socket.set('log level', 1);
//initiate the counter.
counter=0;
counterp=0;
//3. on client connect.
//http://<address>/apps/press_k
socket.on('connection', function(socket){
console.log("Client connected.");
//increment counter on clients command.
socket.on('s_increment_counter',function(data){
counter++;
console.log('New counter:'+counter);
});
//send the counter to all clients if it has increased.
increment_time_continuously();
function increment_time(){
//this is the condition that is to limit how often node sends to the clients,
//but setting it on means the counter will be delivered in some erratic way
//to the clients.
//if(counter===counterp) {return;}
//send current counter to all clients.
console.log("passed the equals, now broadcast.");
//this part is clearly only sending to one of them.
socket.emit('c_display_counter', counter);
//client.broadcast.emit('c_display_counter', counter)
//client.send('Welcome client');
counterp=counter;
}
function increment_time_continuously(){setInterval(increment_time,50);}
});
Relevant client part:
//client_to_server:
//-tell server to increment counter.
function s_increment_counter(){
socket.emit('s_increment_counter',{counter:0});
}
//server_to_client:
//-when server tells to display counter, display counter.
socket.on('c_display_counter',function(counter){
//counter=data["counter"];
k_counter_text.attr({"text":counter});
});
The problem is that you dont store your connections and when you broadcast with socket.emit it goes only to your last connection, you need to store each connection (in a array or something) that has connected to the socket and then iterate over all your connections and broadcast the message you want.
var http=require('http');
var io=require('socket.io');
var fs=require('fs');
var sockFile=fs.readFileSync('text');
server=http.createServer();
//2. get request, via port, http://localhost:8000
server.on('request', function(req, res){
console.log('request received');
res.writeHead(200, {'content-type':'text/html'});
res.end(sockFile);
});
//have server and socket listen to port 8000.
server.listen(8000);
var socket=io.listen(server);
//the lower the number the less chatty the debug becomes.
socket.set('log level', 1);
//initiate the counter.
counter=0;
counterp=0;
connections = {};
function broadcastToConnections(){
for(c in connections){
var con = connections[c];
con.emit('c_display_counter', counter);
}
}
function connectionClose(socket){
delete connections[socket.id];
}
//3. on client connect.
//http://<address>/apps/press_k
socket.on('connection', function(socket){
console.log("Client connected.");
//increment counter on clients command.
socket.on('s_increment_counter',function(data){
counter++;
console.log('New counter:'+counter);
broadcastToConnections();
});
connections[socket.id] = socket;//here we store our connection in connections obj
socket.on('close', connectionClose);//we listen to close event to remove our connection from connection obj
});

Socket.io message event firing multiple times

I was trying to learn node and started creating a mashup with socket.io
The message transportation have begin but I have run into some trouble.
The message event is firing multiple times leading to a single message appearing multiple times on the recipient's box. I have routed the socket to exports.chat and was wondering if that is causing the problem?
To narrow down the problem: the messages are firing the number of times = the sequence of connection of the client. That is, if a client connects second, his messages will fire twice. three times for the client connecting third.
Here is the code snippet:
exports.chat = function(io, pseudoArray, req, res){
res.render('chat', {title: 'ChatPanel.'});
var users = 0;
io.sockets.on('connection', function (socket) { // First connection
users += 1;
// reloadUsers(io, users);
socket.on('message', function (data) { // Broadcast the message to all
if(pseudoSet(socket)) {
var transmit = {date : new Date().toISOString(), pseudo : returnPseudo(socket), message : data};
socket.broadcast.emit('message', transmit);
console.log("user "+ transmit['pseudo'] +" said \""+data+"\"");
}
});
socket.set('pseudo', req.session.user, function(){
pseudoArray.push(req.session.user);
socket.emit('pseudoStatus', 'ok');
console.log("user " + req.session.user + " connected");
});
socket.on('disconnect', function () { // Disconnection of the client
users -= 1;
// reloadUsers();
if (pseudoSet(socket)) {
var pseudo;
socket.get('pseudo', function(err, name) {
pseudo = name;
});
var index = pseudoArray.indexOf(pseudo);
pseudo.slice(index - 1, 1);
}
});
});
};
The whole part of socket.io code has to go outside external.chat function. Socket IO has to bind with the http/app server, you should not handle it within each request.
the messages are firing the number of times = the sequence of connection of the client
What essentially happening is, each time a new request arrives you are registering a event handler for message, hence it is fired as many times as the you have accessed chat URL.
io.socket.on('message', function (data) {...})
So I had the same problem. The solution is to close all your listeners on the socket.on('disconnect') event, this is what my code looks like -
socket.on('disconnect', function () {
socket.removeAllListeners('send message');
socket.removeAllListeners('disconnect');
io.removeAllListeners('connection');
});
Might not need to call it on disconnect, not sure but I do it anyway.
I think this misbehavior is because you are attempting to use one of the handful of built-in/reserved event names "message" as an application-specific message. To confirm, change your event name to "message2" or something else and see if the problem goes away. I believe at least "connect", "disconnect", and "message" are reserved. https://github.com/LearnBoost/socket.io/wiki/Exposed-events
Link: https://socket.io/docs/v3/listening-to-events/#socketoffeventname-listener
Please use socket.off method to removes the specified listener from the listener array for the event named eventName.
socket.off("message").on("message", this.UpdateChat);
Restarting the server can be responsible for several identical event listeners on the client side. If the client has not reloaded (restarted) you have to make sure that the old event listeners are deleted on the client side when establishing a new connection. You can do that with
io.socket.removeAllListeners()
SOCKET.IO v3.x
I don't really know why reserve event in socket.io are firing up multiple times, hence I make a logic that fits to our needs and address this problem,
I simply create a global mutable value that could change everytime the 'disconnect' fire up, here's the logic I did
let ACTIVE_USERS = []; //assume the propery of an object is { name, socket_id }
const connections = (socket) => {
socket.on("disconnect", (reason) => {
//lets check how many times it fires up
console.log('YOW', reason);
//mutate the ACTIVE_USERS
ACTIVE_USERS = ACTIVE_USERS .filter(user => {
//lets figure it out if this thing helps us
if(user.socket_id === socket.id){
console.log('HEY!!!');
socket.broadcast.emit('disconnected-user',[
message: `${user.name} has been disconnected`
})
}
})
});
}
and the result of it is here

Categories