Web Socket: cannot detect client connection on internet disconnect - node.js

I want to detect the client connection if client turn off the internet using web socket. My code is:
//Include util library
var util = require('util');
// Include underscore library
var _ = require('underscore')._;
//For websocket
var webSocketServer = new (require('ws')).Server({port: (process.env.PORT || 5000)}),
webSockets = {} // userID: webSocket
// CONNECT /:userID
// wscat -c ws://localhost:5000/1
webSocketServer.on('connection', function (webSocket)
{
var userID = webSocket.upgradeReq.url.substr(1);
//console.log('User_id is ',userID);
webSockets[userID] = webSocket
util.log('User_id: [' + userID + '] enter in connected users list of [ ' + Object.getOwnPropertyNames(webSockets)+' ]')
// Call function which check id exist in letswalkee DB table
check_userid(userID);
// Send msg like: [fromUserID, text] [1, "Hello, World!"]
webSocket.on('message', function(message) {
util.log('Received from [' + userID + ']: ' + message)
var messageArray = JSON.parse(message)
var toUserWebSocket = webSockets[messageArray[0]]
if (toUserWebSocket) {
util.log('Sent to [' + messageArray[0] + ']: ' + JSON.stringify(messageArray))
messageArray[0] = userID
toUserWebSocket.send(JSON.stringify(messageArray))
}
})
webSocket.on('close', function ()
{
delete webSockets[userID]
util.log('User_id Deleted from connected users: [ ' + userID+' ]');
})
webSocket.on('disconnect',function()
{
console.log('hello i am disconnected');
});
})
I used that code (webSocket.on('disconnect',function()) but did not worked.

WebSocket is based on TCP and TCP uses FIN packet to close the connection. In the case of sudden loss of Internet connection, both the WebSocket server and the phone are unaware of the already dead TCP connection because no FIN packet was sent.
To address the issue, TCP has a mechanism called keepalive.
What I did to solve the issue is adjusting the TCP keepalive settings in Linux kernel, and invoke ws._socket.setKeepAlive(true).
Reference:
https://github.com/websockets/ws/issues/353

For TCP-based protocols (e.g. Websockets) generally what is done is heartbeat/ping packets are sent back and forth at the application layer so that each side can easily/quickly determine if the connection is gone for one reason or another.

Related

Combining Nodejs Net socket and Socket IO

I have a windows application (Built on C# as windows service) that sends data to NodeJs Net Socket, So since Socket.IO helps making a Web Application a live one , without the need of reload. How can i allow Socket.IO stream the received data from NodeJs Net Socket to the Web Application , in the exact moment the Net Socket receives data from C#?
So in the code that receives the socket data from C#:
var net = require('net');
net.createServer(function (socket) {
socket.on('data', function (data) {
broadcast(socket.name + "> \n" + data + " \n", socket);
socket.end("<EOF>");
//send data to web interface , does it work that way?
//SomeFooToSendDataToWebApp(Data)
});
});
Further more for the Socket.IO i have those lines , which i cant really figure out how to deal with them:
//Should it listen to net socket or web socket?
server.listen(8080);
// Loading socket.io
var io = require('socket.io').listen(server);
// It works but only for one request
io.sockets.on('connection', function (socket2) {
socket2.emit('message' , 'Message Text');
});
P.S: I am new to nodejs & socket.io , so if its possible as well to explain their behavior.
Edit 1 : My Front End Javascript to check it if it has any problems:
//for now it listens to http port , which Socket.IO listens to
var socket = io.connect('http://localhost:8080');
var myElement = document.getElementById("news");
socket.on('message', function(message) {
document.getElementById("news").innerHTML = message;
})
Edit 2 : Did follow jfriend00's answer as it seems my previous code tries were trying to send messages to an unknown socket, i only added this since i needed it to be sent to all the connected clients , so only one line fixed it !
socket.on('data', function (data) {
broadcast(socket.name + "> \n" + data + " \n", socket);
socket.end("<EOF>");
//send data to web interface , does it work that way?
//The Added code here:
io.emit('message',data + " more string");
});
It's a bit hard to tell exactly what you're asking.
If you have some data you want to send to all connected socket.io clients (no matter where the data came from), then you can do that with:
io.emit("someMessage", dataToSend);
If you want to send to only one specific connected client, then you have to somehow get the socket object for that specific client and then do:
socket.emit("someMessage", dataToSend);
How you get the specific socket object for the desired connected client depends entirely upon how your app works and how you know which client it is. Every socket connection on the server has a socket.id associated with it. In some cases, server code uses that id to keep track of a given client (such as putting the id in the session or saving it in some other server-side data). If you have the id for a socket, you can get to the socket with the .to() method such as:
io.to(someId).emit("someMessage", dataToSend);
Your question asked about how you send data received from some C# service over a normal TCP socket. As far as sending it to a socket client, it does not matter at all where the data came from or how you received it. Once you have the data in some Javascript variable, it's all the same from there whether it came from a file, from an http request, from an incoming TCP connection in your C# service, etc... It's just data you want to send.
You can try the following, simple server:
const io = require('socket.io')(8080);
io.on('connection', socket => {
console.log('client connected');
socket.on('data', data => {
io.emit('message', data);
});
});
console.log('server started at port 8080');
It should work if I understand the problem correctly.
And maybe document.getElementById("news").innerHTML += message; in the html client code to see what really happens there?
socket2 means your client which just connected. So you can store these connections to send data to them (helpful for broadcast).
If you get data from windows service via some polling mechanism, on this step you can send this message to your connected clients. So keep your connections in a array to send specific messages each client afterwards

Setting up a Stateless connection with NodeJS and Socket.IO

After prototyping my project using PHP and Unity3D i've decided on building the production version using Cordova and NodeJS.
I'm currently using Socket.io with NodeJS and having some confusion with connections. The way that I had expected this to work out was the following procedure:
The client would connect to the server with a request
The server would respond to the request
The connection would be closed
However, it seems that the connection likes to stay open, and if the connection is closed, it continuously attempts to reconnect which is not what I am looking for. I'm attempting to establish a single state of data transfer, similar to what happens when you make a web-request to a PHP file.
The source code of the project is pretty much boilerplate code:
var application = require('express')();
var http = require('http').Server(application);
var server = require('socket.io')(http);
http.listen(8080, function() {
console.log('Listening on *:8080');
});
server.on('connection', function(socket) {
console.log('SERVER: A new connection has been received.');
server.on('disconnect', function() {
console.log('SERVER: A connection has been closed.');
});
});
I do not need a persistent connection, nor do I want one.
Thoughts: I could send a close handshake from the client. For example:
Send some data to the server
Recieve some data from the server
Send a close request to the server / just close the socket
Continue application logic once the socket is closed
Would this be the proper way to handle this? However then the question arises, what if the data gets lost, then there's a permanently open socket. Would implementing a basic timeout be ideal in this situation? (IE: If a response isn't received within 10 seconds, there was an error or the server was not available).
Then Socket.io is the wrong tool for your scenario. socket.io needs to keep the socket open to get events from the server back to the client (and vice-versa). As a matter of fact, even of the server does not support WebSockets, socket.io will resort back to other mechanisms, such as polling.
Not sure why you're using socket.io for this. Socket IO is used for different purpose and doesn't fir your criteria here. I have seen mainly its uses in real time application and binary streaming.You can try TCP socket in node.js
var net = require('net');
var HOST = '127.0.0.1';
var PORT = 6969;
// Create a server instance, and chain the listen function to it
// The function passed to net.createServer() becomes the event handler for the 'connection' event
// The sock object the callback function receives UNIQUE for each connection
net.createServer(function(sock) {
// We have a connection - a socket object is assigned to the connection automatically
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
// Add a 'data' event handler to this instance of socket
sock.on('data', function(data) {
console.log('DATA ' + sock.remoteAddress + ': ' + data);
// Write the data back to the socket, the client will receive it as data from the server
sock.write('You said "' + data + '"');
});
// Add a 'close' event handler to this instance of socket
sock.on('close', function(data) {
console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
});
}).listen(PORT, HOST);
console.log('Server listening on ' + HOST +':'+ PORT);
Check out here

Is it possible to enable tcp, http and websocket all using the same port?

I am trying to enable tcp, http and websocket.io communication on the same port. I started out with the tcp server (part above //// line), it worked. Then I ran the echo server example found on websocket.io (part below //// line), it also worked. But when I try to merge them together, tcp doesn't work anymore.
SO, is it possible to enable tcp, http and websockets all using the same port? Or do I have to listen on another port for tcp connections?
var net = require('net');
var http = require('http');
var wsio = require('websocket.io');
var conn = [];
var server = net.createServer(function(client) {//'connection' listener
var info = {
remote : client.remoteAddress + ':' + client.remotePort
};
var i = conn.push(info) - 1;
console.log('[conn] ' + conn[i].remote);
client.on('end', function() {
console.log('[disc] ' + conn[i].remote);
});
client.on('data', function(msg) {
console.log('[data] ' + conn[i].remote + ' ' + msg.toString());
});
client.write('hello\r\n');
});
server.listen(8080);
///////////////////////////////////////////////////////////
var hs = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type' : 'text/html'
});
res.end(['<script>', "var ws = new WebSocket('ws://127.0.0.1:8080');", 'ws.onmessage = function (data) { ws.send(data); };', '</script>'].join(''));
});
hs.listen(server);
var ws = wsio.attach(hs);
var i = 0, last;
ws.on('connection', function(client) {
var id = ++i, last
console.log('Client %d connected', id);
function ping() {
client.send('ping!');
if (last)
console.log('Latency for client %d: %d ', id, Date.now() - last);
last = Date.now();
};
ping();
client.on('message', ping);
});
You can have multiple different protocols handled by the same port but there are some caveats:
There must be some way for the server to detect (or negotiate) the protocol that the client wishes to speak. You can think of separate ports as the normal way of detecting the protocol the client wishes to speak.
Only one server process can be actually listening on the port. This server might only serve the purpose of detecting the type of protocol and then forwarding to multiple other servers, but each port is owned by a single server process.
You can't support multiple protocols where the server speaks first (because there is no way to detect the protocol of the client). You can support a single server-first protocol with multiple client-first protocols (by adding a short delay after accept to see if the client will send data), but that's a bit wonky.
An explicit design goal of the WebSocket protocol was to allow WebSocket and HTTP protocols to share the same server port. The initial WebSocket handshake is an HTTP compatible upgrade request.
The websockify server/bridge is an example of a server that can speak 5 different protocols on the same port: HTTP, HTTPS (encrypted HTTP), WS (WebSockets), WSS (encrypted WebSockets), and Flash policy response. The server peeks at the first character of the incoming request to determine if it is TLS encrypted (HTTPS, or WSS) or whether it begins with "<" (Flash policy request). If it is a Flash policy request, then it reads the request, responds and closes the connection. Otherwise, it reads the HTTP handshake (either encrypted or not) and the Connection and Upgrade headers determine whether it is a WebSocket request or a plain HTTP request.
Disclaimer: I made websockify
Short answer - NO, you can't have different TCP/HTTP/Websocket servers running on the same port.
Longish answer -
Both websockets and HTTP work on top of TCP. So you can think of a http server or websocket server as a custom TCP server (with some state mgmt and protocol specific encoding/decoding). It is not possible to have multiple sockets bind to the same port/protocol pair on a machine and so the first one will win and the following ones will get socket bind exceptions.
nginx allows you to run http and websocket on the same port, and it forwards to the correct appliaction:
https://medium.com/localhost-run/using-nginx-to-host-websockets-and-http-on-the-same-domain-port-d9beefbfa95d

node.js calculating bandwidth usage by domain

How can I monitor the bandwidth usage of each domain using node.js as the web server?
Does anyone know of an API call I haven't come across to do this?
Or a module or another method which others have used in a multi-tenant environment where you are charging by bandwidth?
Update:
Does anyone know of a lightweight proxy / server which could be put in front of any web server (node.js, apache, etc) which can record these bandwidth stats by inspecting the domain?
Without modifying the node.js core, the best option seems to be to track it at the socket level using the bytesRead and bytesWritten variables.
This is actually more accurate than merely measuring the size of http request / response string as some other bandwidth trackers do to calculate data transferred.
You have 2 options: 1) log the bytes at each request OR 2) log the bytes on the TCP connection close.
Logging on the request level will provide real-time data which could be useful. However, it is likely to slow things down depending on how you implement the logging. It is probably best to keep it in memory and dump it to disk / DB every so often.
Log at request level:
var http = require('http');
var server = http.createServer(function (req, res) {
// setup a counter for bytes already logged
req.connection.bytesLogged = (req.connection.bytesLogged || 0);
// output the bytes read by the socket
console.log('Socket [' + req.connection.remoteAddress + '] [' + req.headers.host + '] - Bytes Read: ' + req.connection.bytesRead);
// calculate the bytes of the request (includes headers and other tcp overhead - more realistic)
req.bytes = req.connection.bytesRead - req.connection.bytesLogged;
// output the bytes size of the request (note this is calculated after the TCP packets have been collected from the network and parsed by the HTTP parser
console.log('Request [' + req.connection.remoteAddress + '] [' + req.headers.host + '] - Bytes: ' + req.bytes);
// log the bytes to a memory array, DB or disk (implementation not shown)
// [code here]
// add the request bytes to the counter
req.connection.bytesLogged = req.connection.bytesLogged + req.bytes;
// normal http server processing like return document or file
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('ok');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.1.1:1337/');
Log at socket level:
var http = require('http');
var server = http.createServer(function (req, res) {
// create some variables for data we want to log
//
// due to the way node.js works the remoteAddress and remotePort will not
// be available in the connection close event
// we also need to store the domain/host from the http header because the http
// request also won't exist when the connection close event runs
var remoteAddress = req.connection.remoteAddress;
var remotePort = req.connection.remotePort;
var host = req.headers.host;
var connection = req.connection;
// output bytes read by socket on each request
console.log('HTTP Request [' + remoteAddress + ':' + remotePort + '] [' + host + '] - connection Bytes Read: ' + connection.bytesRead);
// setup handle for connection close event
//
// to avoid the handle being added multiple times we add the handle onto
// the connection object which will persist between http requests
//
// we store the handler so we can check whether it has already been added
// to the connection listeners array - a less robust alternative would be to
// add a flag like connection.closeHandleAdded = true
connection.handle = connection.handle || {};
if (!connection.handle.onconnectionClose) {
connection.handle.onconnectionClose = function() {
onconnectionClose(remoteAddress, remotePort, host, connection.bytesRead);
}
}
// check whether the close handle has already been added to the connection
// if not add it
if(connection.listeners('close').indexOf(connection.handle.onconnectionClose) == -1)
{
// attach handler to connection close event
connection.on('close', connection.handle.onconnectionClose);
// set connection idle timeout to 5 secs for testing purposes (default is 2min)
connection._idleTimeout = 5000;
}
// process http request as required
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('ok');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.1.1:1337/');
function onconnectionClose (remoteAddress, remotePort, host, bytesRead) {
console.log('connection Closed [' + remoteAddress + ':' + remotePort + '] [' + host + '] - connection Bytes Read: ' + bytesRead);
}
You should have a look at Http Trace.
It is a node.js module that captures, decodes and analyses HTTP and WebSocket traffic.
It can find the size and domain for each request, so with some tweaking, you should be able to do what you want to accomplish here.
It is working well on my Ubuntu server with node v0.6.15, all I had to do was to "apt-get install libpcap0.8-dev".
Try to use this module to measure HTTP response/request: https://github.com/hex7c0/transfer-rate
Data is sent between a client and a server by a socket. Each HTTP response/request has their own socket. The module gets sent-byte in the socket (socket.bytesWritten for the response, and socket.bytesRead for the request). The time for sending the data is calculated by a command (process.hrtime(start)). Then, we divide the results to get the actual transmitted rate.

How can I send packets between the browser and server with socket.io, but only when there is more than one client?

In my normal setup, the client will emit data to my server regardless of whether or not there is another client to receive it. How can I make it so that it only sends packets when the user-count is > 1? I'm using node with socket.io.
To do this you would want to listen to the connection event on your server (as well as disconnect) and maintain a list of clients which are connected in a 'global' variable. When more than 1 client is connected send out a message to all connected clients to know they can start sending messages, like so:
var app = require('express').createServer(),
io = require('socket.io').listen(app);
app.listen(80);
//setup express
var clients = [];
io.sockets.on('connection', function (socket) {
clients.push(socket);
if (clients.length > 1) {
io.socket.emit('start talking');
}
socket.on('disconnect', function () {
var index = clients.indexOf(socket);
clients = clients.slice(0, index).concat(clients.slice(index + 1));
if (clients.length <= 1) {
io.sockets.emit('quiet time');
};
});
});
Note: I'm making an assumption here that the socket is passed to the disconnect event, I'm pretty sure it is but haven't had a chance to test.
The disconnect event wont receive the socket passed into it but because the event handler is registered within the closure scope of the initial connection you will have access to it.

Resources