node.js calculating bandwidth usage by domain - node.js

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.

Related

Whether load gets distributed when reading from two ports rather than single port from 50k concurrent connections

I am having a simple server program which just reads and sends reply back to the client. Am connecting 1000 clients pumping 4096 bytes of data concurrently and continuously. But my server is getting crashed showing out of memory error. My analysis is that messages are getting accumulated in the buffer.
My doubt is when i have two different ports in the same server receiving from 500 clients each may decrease accumulation of message in the buffer?
Please help me on this.
My node js code for server
var net = require('net');
var readline=require('readline');
var HOST = '10.44.75.21';
var PORT = 6969;
net.createServer(function(sock) {
var i = readline.createInterface(sock, sock);
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
// Add a 'data' event handler to this instance of socket
i.on('line', function(data) {
//console.log('Application Name : ' + data);
// Write the data back to the socket, the client will receive it as data from the server
sock.write('Connected to "' + data + '\n"');
});
// 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);
That's highly unlikely to make a difference.
JavaScript is single-threaded. Whether you have 1 listen port, or N listen port is irrelevant. Requests will be handled one after the other, and the incoming port shouldn't make any impact on memory usage.
A better solution is to put a load-balancing reverse proxy in front of multiple instances of the same server logic, where each instance is listening to a different port.
With enough load, this will fail as well, but it will buy you some time.
Combined with an auto-recovery scheme this will guarantee your server is always ready to handle requests.

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

Web Socket: cannot detect client connection on internet disconnect

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.

node.js http server: how to get pending socket connections?

on a basic node http server like this:
var http = require('http');
var server = http.createServer(function(req, res){
console.log("number of concurr. connections: " + this.getConnections());
//var pendingConnections = ???
});
server.maxConnections = 500;
server.listen(4000);
if i send 500 requests at one time to the server, the number of concurr. connections is arround 350. with the hard limit set to 500 (net.server.backlog too), i want to know, how to access the number of pending connections (max. 150 in this example) when ever a new request starts.
so i think i have to access the underlying socket listening on port 4000 to get this info, but until now i was not able to get it.
EDIT
looking at node-http there is an event called connection, so i think the roundtrip of an request is as follows:
client connects to server socket --> 3-way-handshake, socket lasts in state CONNECTED (or ESTABLISHED ?!) then in node event connection is emitted.
the node http server accepts this pending connection an starts processing the request by emitting request
so the number of connections has to be at least as big as the number of requests, but with following example i could not confirm this:
var http = require('http');
var activeRequets = 0;
var activeConnections = 0;
var server = http.createServer(function(req, res){
activeRequests++;
res.send("foo");
});
server.on('connection', function (socket) {
socket.setKeepAlive(false);
activeConnections++;
});
setInterval(function(){
console.log("activeConns: " + activeConnections + " activeRequests: " + activeRequests);
activeRequests = 0;
activeConnections = 0;
}, 500);
server.maxConnections = 1024;
server.listen(4000, '127.0.0.1');
even if i stress the server with 1000 concurr connections and adding one delay in the response, activeRequests is mostly as high as activeConnections. even worse, the activeRequests are often higher then activeconnections, how could this be?
IIRC You can just count how many connections that have a status of SYN_RECV for that particular IP and port that you're listening on. Whether you use a child process to execute netstat and grep (or similar utilities) for that information, or write a binding to get this information using the *nix C API, is up to you.

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

Resources