Reputation: 3084
Using socket.io v1.2.1 (only using the "polling" transport), sometimes my clients experience disconnections.
About 50% of the time I get ping timeout
on my disconnect event callback function, which is reasonable.
Other times, I get transport close
, client namespace disconnect
, transport error
and forced close
. I did not find any reference to those disconnection reasons in the documentation, and was not able to really understand their meaning from the code.
I want to make sure I handle each disconnection the best way (and maybe prevent them).
Maybe someone can shed a little light about these reasons.
Upvotes: 19
Views: 39791
Reputation: 381
I had a similar situation where too many updates from server to client (around 2000 in a matter of seconds) seemed to cause a forced close of the connection. Sending updates less often solved the problem.
I haven't had a chance yet to find out whether this was caused by socket.io itself, or some firewall/server mechanism. Maybe because flooding the connection between server and client messes up the heartbeat mechanism, although client-side log doesn't show that.
Although the exact cause is not found yet, maybe this can point some people into the right direction to find a solution.
Upvotes: 0
Reputation: 151
Try this code at server side
var fs = require('fs');
var pkey = fs.readFileSync('/etc/ssl/private/ssl.key'); //Replace the path of your SSL key
var pcert = fs.readFileSync('/etc/ssl/certs/ssl.crt');//Replace the path of your SSL cert
var options = {
key: pkey,
cert: pcert
};
var app = require('https').createServer(options);
var io = require('socket.io')(app, {'pingTimeout': 180000, 'pingInterval': 25000});
Here pingInterval
is important, Keep it low, I tried various values and found 25 sec is good to keep socket keep pinging before it get timeout.
The main issue is there if within 60 sec there is no ping/pong, then it will disconnect and try to auto reconnect. Also, I found pingTimeout
at server side and timeout and client side not able to help to disconnect the socket in 60 sec. It's happening due to chrome latest version 83.
Upvotes: 1
Reputation: 350
There is no documentation, this is more or less what i can interpret from the code:
Forced close
- The socket is in closing state
Forced close
- https://github.com/socketio/engine.io/blob/master/lib/socket.js
function onPacket(packet){
if ('ping' == packet.type && 'probe' == packet.data) {
transport.send([{ type: 'pong', data: 'probe' }]);
self.emit('upgrading', transport);
clearInterval(self.checkIntervalTimer);
self.checkIntervalTimer = setInterval(check, 100);
} else if ('upgrade' == packet.type && self.readyState != 'closed') {
debug('got upgrade packet - upgrading');
cleanup();
self.upgraded = true;
self.clearTransport();
self.setTransport(transport);
self.emit('upgrade', transport);
self.setPingTimeout();
self.flush();
if (self.readyState == 'closing') {
transport.close(function () {
self.onClose('forced close');
});
}
} else {
cleanup();
transport.close();
}
}
Socket.prototype.close = function () {
if ('open' != this.readyState) return;
this.readyState = 'closing';
if (this.writeBuffer.length) {
this.once('drain', this.closeTransport.bind(this));
return;
}
this.closeTransport();
};
The transport where closed (no reason here)
Transport close
- https://github.com/socketio/engine.io/blob/master/lib/socket.js
function cleanup() {
self.upgrading = false;
clearInterval(self.checkIntervalTimer);
self.checkIntervalTimer = null;
clearTimeout(self.upgradeTimeoutTimer);
self.upgradeTimeoutTimer = null;
transport.removeListener('packet', onPacket);
transport.removeListener('close', onTransportClose);
transport.removeListener('error', onError);
self.removeListener('close', onClose);
}
function onTransportClose(){
onError("transport closed");
}
We got a client disconnect packet, so we change socket state to 'closing'
Client namespace disconnect
- https://github.com/socketio/socket.io/blob/master/lib/socket.js
Socket.prototype.onpacket = function(packet){
debug('got packet %j', packet);
switch (packet.type) {
case parser.EVENT:
this.onevent(packet);
break;
case parser.BINARY_EVENT:
this.onevent(packet);
break;
case parser.ACK:
this.onack(packet);
break;
case parser.BINARY_ACK:
this.onack(packet);
break;
case parser.DISCONNECT:
this.ondisconnect();
break;
case parser.ERROR:
this.emit('error', packet.data);
}
};
Socket.prototype.ondisconnect = function(){
debug('got disconnect packet');
this.onclose('client namespace disconnect');
};
One of the reasons of transport close
Transport error
- https://github.com/socketio/engine.io/blob/master/lib/socket.js
/**
* Called upon transport error.
*
* @param {Error} error object
* @api private
*/
Socket.prototype.onError = function (err) {
debug('transport error');
this.onClose('transport error', err);
};
https://github.com/socketio/engine.io/blob/master/lib/transport.js
/**
* Called with a transport error.
*
* @param {String} message error
* @param {Object} error description
* @api private
*/
Transport.prototype.onError = function (msg, desc) {
if (this.listeners('error').length) {
var err = new Error(msg);
err.type = 'TransportError';
err.description = desc;
this.emit('error', err);
} else {
debug('ignored transport error %s (%s)', msg, desc);
}
};
It seems like they throw errors to sockets from everywhere, so the only way of find the cause is by reading the error description (not too much information) or looking all their libraries to find what is causing the error.
PD: there are a lot of errors.
Upvotes: 6
Reputation: 2757
Unfortunately this may happen. Sometimes, as I had misfortune to deal with, it was due to firewall somewhere in between me, server and other client.
For ping timeouts you may try to increase ping interval on server side
io = require( 'socket.io' )( httpServer, { pingInterval: 60000 } );
Upvotes: -2