socket.io 'disconnect' not called if page refreshed fast enough - javascript

I have the following abridged code:
io.on('connection', function(client) {
client.uuid = uuid.v4();
// add client object to server...
console.log('socket.io:: client connected ' + client.uuid );
client.on('disconnect', function() {
console.log('socket.io:: client disconnected ' + client.uuid );
// remove client object from server...
});
});
If I open up this page in the browser, everything seems fine. If I refresh the page, it will fire disconnect and then connection. However, if I refresh fast enough, there are times where disconnect doesn't get called and thus client data doesn't get cleaned from the server. Is there any way to protect from this?
Edit: reword reconnect -> connection

As adeneo mentioned, socket.io has heartbeats which automatically check to see if a client is still connected. The disconnect code is fired if it detects the client is actually gone. After replicating my original issue, I tried leaving the server on, and about 30 seconds later, the "dead" clients were being removed. So to solve the issue, you just have to wait. Socket.io takes care of everything on its own.

The same question was answered here.
TL;DR
You can use those options on the client:
const socket = io({
transports: ['websocket'],
upgrade: false
});
This will prevent socket.io from using the HTTP polling method at all, which causes the issues. I used this trick successfully on v4.

Related

Detect client's disconnection WebSocket

I'm using WebSocket & nodeJs. I can detect user's connection and present it, but I can't detect user's disconnetion. The method on('close',function()....) happens when I shut down the server and not when a user closes the tab or something. What can I do? I realy don't know how to do it right now. Thank you all! Hoping you'll help me.
To detect socket disconnection, I use this method which works fine :
socket.once('disconnect', function () {
// socket is disconnected
});
Or
socket.on('disconnect', function () {
// socket is disconnected
});
Hope it helps.
You should implement heartbeat requests (inside websocket connection) from client to server (every 20-30 sec) and limit connection to some period (40-50 sec) - this can be done in web server (or even load balancer settings).
When server find that there is no heartbeat request it means that this connection is broken - client closed tab or something.
Updated: oh! Seems socket.io have heartbeat implementation, so my answer was a bit common.
io.sockets.on('connection',function(socket){
socket.on('disconnect', function(){
// Your stuff here
});
});

autobahn (node) not detecting dropped connect, infinite wait, can I set a timeout?

I'm using this AutobahnJS code in node to receive data from a service. It works great, getting multiple events per second. When my internet temporarily disconnects Autobahn does not detect the lost connection and does not write "Websocket connection dropped" to console, it just hangs. Indefinitely.
Is there a timeout one can set, if no data arrives after 1 minute, reconnect? Or can I use a setTimeout function to ping a server and if no pong returns close the connection and try to reopen it?
I googled till my fingers were bleeding, but I didn't find a straightforward answer to this question. Thank you very much!
connection.onopen = function(session) {
session.subscribe(arg, someEvent);
}
connection.onclose = function() {
console.log("Websocket connection dropped");
}
connection.open();
It is not possible to recognize an unclean disconnect without some data being sent. The WebSocket ping/pong mechanism at the protocol level is not exposed in the browser, and Autobahn|JS does not have any different handling when running in Node.js.
For the time being, you need to implement your own ping/pong mechanism at the application level.

Correct way to handle Websocket

I've a client to server Websocket connection which should be there for 40 seconds or so. Ideally it should be forever open.
The client continually sends data to server and vice-versa.
Right now I'm using this sequence:
var socket;
function senddata(data)
{
if (!socket)
{
socket = new WebSocket(url);
socket.onopen = function (evt) {
socket.send(data);
socket.onmessage = function (evt) {
var obj = JSON.parse(evt.data);
port.postMessage(obj);
}
socket.oneerror = function (evt) {
socket.close();
socket = null;
}
socket.onclose = function(evt){
socket = null;
}
}
}
else
{
socket.send(data);
}
}
Clearly as per current logic, in case of error, the current request data may not be sent at all.
To be frank it sometimes gives error that websocket is still in connecting state. This connection breaks often due to networking issues. In short it does not work perfectly well.
I've read a better design : How to wait for a WebSocket's readyState to change but does not cover all cases I need to handle.
Also I've Googled about this but could not get the correct procedure for this.
So what is the right way to send regular data through Websockets which handles well these issues like connection break etc?
An event you don't seem to cover is onclose. Which should work really well, since it's called whenever the connection terminates. This is more reliable than onerror, because not all connection disruptions result in an error.
I personally use Socket.IO, it enables real-time bidirectional event-based communication between client and server.
It is event driven. Events such as
on connection :: socket.on('conection',callback);
and
on disconnect :: socket.on('disconnect',callback);
are built in with socket.io so it can help you with your connection concerns. Pretty much very easy to use, check out their site if you are interested.
I use two-layer scheme on client: abstract-wrapper + websocket-client:
The responsibilities of the websocket-client are interacting with a server, recovering the connection and providing interfaces (event-emitter and some methods) to abstract-wrapper.
The abstract-wrapper is a high-level layer, which interacts with websocket-client, subscribes to its events and aggregating data, when the connection is temporary failed. The abstract-wrapper can provide to application layer any interface such as Promise, EventEmitter and so on.
On application layer, I just work with abstract-wrapper and don't worry about connection or data losing. Undoubtedly, it's a good idea to have here information about the status of connection and data sending confirmation, because it's useful.
If it is necessary, I can provide some code for example
This apparently is a server issue not a problem in the client.
I don't know how the server looks like here. But this was a huge problem for me in the past when I was working on a websocket based project. The connection would continuously break.
So I created a websocket server in java, and that resolved my problem.
websockets depend on lots of settings, like if you're using servlets then servlet container's settings matter, if you're using some php etc, apache and php settings matter, for example if you create a websocket server in php and php has default time-out of 30 seconds, it will break after 30 seconds. If keep-alive is not set, the connection wont stay alive etc.
What you can do as quick solution is
keep sending pings to a server after a certain amount of time (like 2 or 3 seconds, so that if a websocket is disconnected it is known to the client so it could invoke onclose or ondisconnect, I hope you know that there is no way to find if a connection is broken other than failing to send something.
check server's keep-alive header
If you have access to server, then it's timeouts etc.
I think that would help

How to reconnect socket.io client on activity after auto-reconnect times out?

It is common for laptops to go to sleep. This causes the socket.io client to disconnect. When the user returns to the web app, the socket.io client doesn't try to reconnect (probably reconnection limit reached?). How do I tell the socket to reconnect if the user does some action?
For example, I'd like the emit function to check if the connection is active, and if not then try to reconnect.
Note: I only need the client-side JS code and I'm not using node.js.
In version 0.9 you could try to set the connect options object to some aggressive settings:
var main = io.connect('/', {
'reconnection delay': 100, // defaults to 500
'reconnection limit': 100, // defaults to Infinity
'max reconnection attempts': Infinity // defaults to 10
});
Note that max reconnection attemps does not mean that the io client will stop to reconnect to the server after 10 failed attempts. If it was able to reconnect to the server 10 times and loses the connection for the 11th time, it will stop to reconnect.
See Socket.IO Configuration
Socket instances have an inner 'socket' property, which in turn has connect() method that you can call. It's normally called automatically when you instantiate the object (controlled by the 'auto connect' option). The inner socket also have a boolean "connected" property which you can check if you're not sure what the state is. Like so:
sio = io.connect();
//... time passes ...
if (! sio.socket.connected) {
sio.connect();
}
The connect() method checks to make sure that the socket isn't in the middle of trying to connect, though for some reason it doesn't check to see if it's already connected. Not sure what happens if you connect() an already-connected socket...
The source code for the client library is fairly clear and well commented, which is good since the README on github doesn't provide a whole lot of help. It's handy to use an un-minified version of the library while you're doing development so you can dig into the source.
You could try to use the connect.failed event:
socket.on('connect_failed', function () {
/* Insert code to reestablish connection. */
});
You could have a setInterval running which checks connected status like
s.connect()
if (! s.socket.connected) {
s.connect();

Memory leaks using socket.io

I've found that sockets are not fully destroyed in socket io server side when manually disconnecting them. I've found this topic on github useful. While I'm looking for some variable-links that prevent GC from cleaning sockets, I'm asking a question here.
If anyone here encountered the same problem, this would be much help.
the code that does not work:
socket.on('disconnect', function(){
socket.removeAllListeners();
});
///...................
socket.disconnect();
Workaround that, however, uses restricted library fields:
delete io.sockets[url];
io.j = [];
actually, this is working as intended, when you disconnect a socket you simply state you're not expecting to receive any more data from that socket right now, to actually destroy the socket you basically do the delete socket action. Use this on the disconnect event, ie:
socket.on('disconnect', function(){
delete socket;
})
you can also do this on the io.sockets.sockets Object on an external function:
function deleteSocket(socketID){
delete io.sockets.sockets[socketID];
}

Categories

Resources