How many times can Socket.io 'connection' and 'disconnection' events be fired for single client? - node.js

EDIT: I see that I'm getting ping timeout and transport error reasons in my handler for disconnect on the server. This makes it difficult to maintain state in my server (I'm trying to keep track of which users are connected in a chat-like setup(. I was reading that it may be related to background tabs in Chrome (which I'm running). Does anyone have any experience with these 'spurious' disconnect events?
I'm new to Socket.io and am having some trouble understanding the connection and disconnection process.
As I understand it, the server receives the connection event once when a client connects, and one registers all the handlers for that client in the callback on on.('connection'). Is that true?
I want to maintain an of connected users, so I add a user to that array on the connection handler.
Should I then listen for the disconnect event to know when to remove a user from that array? Can I be guaranteed that that event will only be fired once?
It's a bit confusing, because on the client side, there is the connect event, which apparently can be fired multiple times -- the documentation says
// note: you should register event handlers outside of connect,
// so they are not registered again on reconnection
which is a different paradigm than on the server side, where all the handlers are registered inside the connection handler. But if the client-side connect event can fire on re-connection, what is the reconnect event for? (The docs says this event is "Fired upon a successful reconnection.")
In general I'm confused about the process of connection, disconnection and re-connection and how this relates to events, whether it happens "randomly" due to connection issues or only under the programmer's control, and how many times one should anticipate receiving each of these events -- once only for server, multiple times for client?
Thanks for any help!

I'm new to Socket.io and am having some trouble understanding the
connection and disconnection process.
Welcome to the wonderful world of Node.js + Socket.io It's super powerful!
As I understand it, the server receives the connection event once when
a client connects, and one registers all the handlers for that client
in the callback on on.('connection'). Is that true?
Correct. Take a look at this example of my code:
Server-side
var clients = []; /* stores all sockets on the fly */
io.on('connection', function (socket) {
clients[socket.id] = socket; /* keeps an array of sockets currently connected */
socket.on('disconnect', function (data) {
console.log(socket.id + " disconnected");
delete clients[socket.id];
});
});
Client-side
socket = io.connect(YOUR_SOCKET_URI, { transports: ['websocket'] } );
socket_delegates();
socket_delegates = function() {
// Socket events
socket.on('connect', function(data) {
/* handle on connect events */
});
socket.on('disconnect', function () {
/* handle disconnect events - possibly reconnect? */
});
socket.on('reconnect', function () {
/* handle reconnect events */
});
socket.on('reconnect_error', function () {
/* handle reconnect error events - possible retry? */
});
}
Should I then listen for the disconnect event to know when to remove a
user from that array? Can I be guaranteed that that event will only be
fired once?
Yes. You will see in the above server code that we listen for disconnect and then do what we need to.
Nothing should be random. You should have code in place to handle the connect, disconnect on the server side and code to handle the connect, disconnect and reconnect on the client side.

Related

Attaching event emitter to socket.connected

I am currently writing an Electron app, for which in the main process I want to talk to a server over websockets.
Part of my main process' code base depends on the user's socket connection status. I require the socket.io-client library
const socket = require('socket.io-client')(host);
which gives me access to the variable socket.connected, which is true or false according to whether a connection is established to the server.
Thus, what I would like is to attach an event emitter to this variable. I have made it to work with polling
var events = require('events').EventEmitter;
var event = new events();
// Emits successfully every 200ms 'Connection: true|false'
event.on('status', function(status){
console.log('Connection: ', status);
});
setInterval(function() {
let status = socket.connected;
event.emit('status', status);
}, 200);
but was wondering whether this truly is the way to implement it. To me it seems strange to have to resort to polling in an async framework like nodejs. On the other, I could not find other ways to implement. Best-case scenario would be to attach somehow an event emitter directly to socket.connected, but was unable to find how to do that. Could anybody advise me on a better way to implement?
Thanks
You can get notified of the completion of a client connection with the connect event:
socket.on('connect', function() {
// client socket is now connected to the server
});
socket.on('disconnect', function() {
// client socket is now disconnected from the server
});
Documentation for client events here: http://socket.io/docs/client-api/#manager(url:string,-opts:object). There are other events in that doc if you also want to see other things like a reconnect.

Node.JS net module handling unexpected connection loss

I can't figure out one problem I got.
I'm using the Net module on my Node.JS server which is used to listen to client connections.
The client do connect to the server correctly and the connection remains available to read/write data. So far, so good. But when the client unexpectedly disconnects (ed. when internet falls away at client side) I want to fire an event server side.
In socket.io it would be done with the 'disconnect' event, but this event doesn't seem to exist for the Net module. How is it possible to do?
I've searched on Google/StackOverflow and in the Net documentation (https://nodejs.org/api/net.html) but I couldn't find anything usefull. I'm sry if I did mis something.
Here is a code snippet I got:
var net = require('net');
var server = net.createServer(function(connection) {
console.log('client connected');
connection.wildcard = false;//Connection must be initialised with a configuration stored in the database
connection.bidirectional = true;//When piped this connection will be configured as bidirectional
connection.setKeepAlive(true, 500);
connection.setTimeout(3000);
connection.on('close', function (){
console.log('Socket is closed');
});
connection.on('error', function (err) {
console.log('An error happened in connection' + err.stack);
});
connection.on('end', function () {
console.log('Socket did disconnect');
});
connection.on('timeout', function () {
console.log('Socket did timeout');
connection.end();
});
connection.on('data', function (data) {
//Handling incoming data
});
});
serverUmrs.listen(40000, function () {
console.log('server is listening');
});
All the events(close, end, error, timeout) don't fire when I disconnect the client(by pulling out the UTP cable).
Thanks in advance!
EDIT:
I did add a timeout event in the code here above but the only thing that happens is that the socket does timeout after 3 seconds everytime the client does connect again. Isn't KeepAlive enough to make the socket not Idle? How is it possible to make the socket not idle without to much overhead. It may be possible that there are more than 10,000 connections at the same time which must remain alive as long as they are connected (ie respond to the keepalive message).
Update:
I think the KeepAlive is not related with the Idle state of socket, sort of.
Here is my test, I remove the following code in your example.
//connection.setKeepAlive(true, 500);
Then test this server with one client connect to it var nc localhost 40000. If there is no message sending to server after 3 seconds, the server logs as below
Socket did timeout
Socket did disconnect
Socket is closed
The timeout event is triggered without KeepAlive setting.
Do further investigation, refer to the Node.js code
function onread(nread, buffer) {
//...
self._unrefTimer();
We know timeout event is triggered by onread() operation of socket. Namely, if there is no read operation after 3 seconds, the timeout event will be emitted. To be more precisely, not only onread but also write successfully will call _unrefTimer().
In summary, when the write or read operation on the socket, it is NOT idle.
Actually, the close event is used to detect the client connection is alive or not, also mentioned in this SO question.
Emitted when the server closes. Note that if connections exist, this event is not emitted until all connections are ended.
However, in your case
disconnect the client(by pulling out the UTP cable).
The timeout event should be used to detective the connection inactivity. This is only to notify that the socket has been idle. The user must manually close the connection. Please refer to this question.
In TCP connection, end event fire when the client sends 'FIN' message to the server.
If the client side is not sending 'FIN' message that event is not firing.
For example, in your situation,
But when the client unexpectedly disconnects (ed. when internet falls away at client side) I want to fire an event server side.
There may not be a 'FIN' message because internet is gone.
So you should handle this situation in timeout without using keepAlive. If there is no data coming data, you should end or destroy the socket.
EDIT: I did add a timeout event in the code here above but the only
thing that happens is that the socket does timeout after 3 seconds
everytime the client does connect again. Isn't KeepAlive enough to
make the socket not Idle? How is it possible to make the socket not
idle without to much overhead. It may be possible that there are more
than 10,000 connections at the same time which must remain alive as
long as they are connected (ie respond to the keepalive message).
For your edit, your devices should send to the server some heartbeat message between a time period. So that, server understands that that device is alive and that timeout event will not fire because you get some data. If there is no heartbeat message such cases you cannot handle this problem.

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).

node.js + socket.io broadcast from server, rather than from a specific client?

I'm building a simple system like a realtime news feed, using node.js + socket.io.
Since this is a "read-only" system, clients connect and receive data, but clients never actually send any data of their own. The server generates the messages that needs to be sent to all clients, no client generates any messages; yet I do need to broadcast.
The documentation for socket.io's broadcast (end of page) says
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
So I currently capture the most recent client to connect, into a variable, then emit() to that socket and broadcast.emit() to that socket, such that this new client gets the new data and all the other clients. But it feels like the client's role here is nothing more than a workaround for what I thought socket.io already supported.
Is there a way to send data to all clients based on an event initiated by the server?
My current approach is roughly:
var socket;
io.sockets.on("connection", function (s) {
socket = s;
});
/* bunch of real logic, yadda yadda ... */
myServerSideNewsFeed.onNewEntry(function (msg) {
socket.emit("msg", { "msg" : msg });
socket.broadcast.emit("msg", { "msg" : msg });
});
Basically the events that cause data to require sending to the client are all server-side, not client-side.
Why not just do like below?
io.sockets.emit('hello',{msg:'abc'});
Since you are emitting events only server side, you should create a custom EventEmitter for your server.
var io = require('socket.io').listen(80);
events = require('events'),
serverEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'newFeed' event
// which will be triggered by the server later on
serverEmitter.on('newFeed', function (data) {
// this message will be sent to all connected users
socket.emit(data);
});
});
// sometime in the future the server will emit one or more newFeed events
serverEmitter.emit('newFeed', data);
Note: newFeed is just an event example, you can have as many events as you like.
Important
The solution above is better also because in the future you might need to emit certain messages only to some clients, not all (thus need conditions). For something simpler (just emit a message to all clients no matter what), io.sockets.broadcast.emit() is a better fit indeed.

Detecting close of client connect in node.js

I am using node.js for long held connections. I want to know how I can detect when the client connection closes (maybe when the user closes the tab). How do I specify a callback for that?
Answering my own question - You can detect close of client connection by doing:
http.createServer(function(request, response) {
request.connection.addListener('close', function () {
// callback is fired when connection closed (e.g. closing the browser)
});
}
Take a look at Socket.io. It supports the following transports with fallbacks in this order:
WebSocket
Adobe Flash Socket
AJAX long polling
AJAX multipart streaming
Forever Iframe
JSONP Polling
The benefit is you'll be able to handle a lot more concurrent connections than long polling alone. In addition you'll get a rich set of features like heartbeats and disconnects.
io.sockets.on('connection', function (socket) {
// ... other socket handlers here ...
socket.on('disconnect', function () {
// do something to handle the disconnect
});
});

Resources