Service multiple connection on NodeJS webserver - node.js

I have a web server running using Node.js with express and socket.io It displays real-time temperature information and allows for real-time control of some basic hardware controllers.
Each time I connect to the server from a different client, a new instance of the content is delivered as opposed to delivering the last configured instance or state.
Things work fine when just one client is used, but I need to be able to monitor the temperatures and control status from multiple clients.
How can I make sure that no matter which client accesses the server, they all see the same state of the server?
Server code below:
var app = require('express')();
var http = require('http').createServer(app);
var socketServer = require('socket.io').listen(http);
var fs = require('fs');
var csv_stream = fs.createWriteStream("tempLog.csv");
var time_handler = require('moment');
SerialPort = require("serialport").SerialPort;
var serialPort;
var portName = '/dev/ttyACM0'; //change this to your Arduino port
var sendData = "";
var debug = false;
app.get('/', function(req, res){
res.sendFile(__dirname + '/public/interface.html')
});
socketServer.on('connection', function(socket){
console.log('a user connected');
socket.on('run', function(data){
serialPort.write('Z' + data + 'A');
console.log('write to ard');
console.log('Z' + data + 'A');
});
socket.on('stop', function(data){
serialPort.write('Y' + data + 'B');
console.log('write to ard');
console.log('Y' + data + 'B');
});
socket.on('configure', function(data){
serialPort.write('X' + data + 'C');
console.log('write to ard');
console.log('X' + data + 'C');
});
socket.on('temperatureValues', function(data){
serialPort.write(data);
console.log('write data to ard');
console.log(data);
});
socket.on('timeValues', function(data){
serialPort.write(data);
console.log('write data to ard');
console.log(data);
});
});
serialListener(debug);
function SocketIO_serialemit(sendData){
//console.log(sendData.length);
if(sendData.length >= 14)
{
var s_data = sendData.split(",");
socketServer.emit('temp1',{'temp': s_data[0]});
socketServer.emit('temp2',{'temp': s_data[1]});
socketServer.emit('temp3',{'temp': s_data[2]});
csv_stream.write(time_handler().format('HH:mm:ss') + ',');
csv_stream.write(s_data[0] + ',' + s_data[1] + ',' + s_data[2]);
csv_stream.write('\n');
//csv_stream.end();
}
else{
console.log("Error");
//var s_data = sendData.split(",");
//console.log(s_data[0]);
//console.log(s_data[1]);
//console.log(s_data[2]);
}
}
// Listen to serial port
function serialListener(debug)
{
var receivedData = "";
serialPort = new SerialPort(portName, {
baudrate: 9600,
// defaults for Arduino serial communication
dataBits: 8,
parity: 'none',
stopBits: 1,
flowControl: false
});
serialPort.on("open", function () {
console.log('open serial communication');
// Listens to incoming data
serialPort.on('data', function(data) {
if (data.toString() == "X")
{
console.log("Control Done");
socketServer.emit('Completed',{'key': data.toString()});
}
if (data.toString()[0] == "S")
{
console.log("Stage Done");
socketServer.emit('Stage',{'key': data.toString()[0]});
}
receivedData += data.toString();
//console.log(receivedData);
if (receivedData .indexOf('E') >= 0 && receivedData .indexOf('T') >= 0) {
sendData = receivedData .substring(receivedData .indexOf('T') + 1, receivedData .indexOf('E'));
receivedData = '';
SocketIO_serialemit(sendData);
}
});
});
}
http.listen(3000, function(){
console.log('listening on *:3000')
});
app.use(require('express').static(__dirname + '/public')); //sever static files (css, js, fonts, etc.)

Related

Nodejs - data transfer between server and client

I was given a task to send JSON string from client to server and from server to client, whenever there is a new record found to send.
I decided to build TCP connection(suggest me if there is any other better way in Node.js) between server and client to transfer data.
The problem is, I was supposed to use a delimiter to separate JSON strings one from another. I am afraid what if the json string contains the delimiter string inside the object. I am looking for a better way to separate two JSON strings.
Below is my code. Please help me.
Client
var net = require('net')
, client = new net.Socket();
var chunk = ''
, dlim_index = -1
, delimit = '~~';
client.connect(config.Port, config.IpAddress, function () {
console.log('Server Connected');
client.write('CLIENTID:' + process.argv[2]);
client.write(delimit);
});
client.on('data', function (data) {
var recvData = data.toString().trim();
chunk += recvData;
dlim_index = chunk.indexOf(recvData);
console.log(data);
while (dlim_index > -1) {
var useData = chunk.substring(0, dlim_index);
if (useData == 'SUCCESS') {
controller.listenOutQueue(function (dataToSend) {
var object = JSON.parse(dataToSend);
client.write(dataToSend);
client.write(delimit);
});
}
else {
var record = JSON.parse(useData);
controller.insertIntoQueue(record, function (status) {
});
}
chunk = chunk.substring(dlim_index + 2);
dlim_index = chunk.indexOf(delimit);
}
});
client.on('close', function () {
console.log('Connection closed');
});
client.setTimeout(50000, function () {
//client.destroy();
});
Server
var net = require('net')
, server = net.createServer()
, delimit = '~~'
, clients = [];
controller.listenOutQueue(function (dataToSend) {
client.write(dataToSend);
client.write(delimit);
});
server.on('connection', function (socket) {
var chunk = '';
var dlim_index = -1;
socket.on('data', function (data) {
var recvData = data.toString().trim();
chunk += recvData;
dlim_index = chunk.indexOf(delimit);
while (dlim_index > -1) {
var useData = chunk.substring(0, dlim_index);
if (useData.substring(0, 9) == 'CLIENTID:') {
socket.clientid = useData.replace('CLIENTID:', '');
console.log('Client Id: ' + socket.clientid);
clients.push(socket);
var successMessage = "SUCCESS";
socket.write(successMessage);
socket.write(delimit);
}
else {
controller.insertIntoQueue(JSON.parse(useData), function (status) {
});
}
chunk = chunk.substring(dlim_index + 2);
dlim_index = chunk.indexOf(delimit);
}
});
socket.on('end', function () {
console.log('Connection Closed (' + socket.clientid + ')');
});
socket.on('error', function (err) {
console.log('SOCKET ERROR:', err);
});
});
server.listen(config.Port, config.IpAddress);

using WiFly with ws websockets

I have been trying to figure out a way to connect a WiFly from an Arduino to send some accelerometer data to my node.js server. Currently the way that I have it worked out is having three servers:
Http >> This is for clients purposes
Net server >> This is basically for TCP request, this is how my server receives the information from 3. WS websockets >> this takes the data from the Net server and streams it to the client side.
Here is the code:
var http = require('http');
var fs = require('fs');
var path = require('path');
var url = require('url');
var net = require('net');
var sensorData;
var message = {
"data": ''
}
var newValue,
oldValue,
diff;
//Settings
var HTTP_PORT = 9000;
var NET_PORT = 9001;
var WS_PORT = 9002;
//Server
var mimeTypes = {
"html": "text/html",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"js": "text/javascript",
"css": "text/css"
};
http.createServer(function (req, res) {
var fileToLoad;
if (req.url == '/') {
fileToLoad = 'index.html';
} else {
fileToLoad = url.parse(req.url).pathname.substr(1);
}
console.log('[HTTP] :: Loading :: ' + 'frontend/' + fileToLoad);
var fileBytes;
var httpStatusCode = 200;
fs.exists('frontend/' + fileToLoad, function (doesItExist) {
if (!doesItExist) {
console.log('[HTTP] :: Error loading :: ' + 'frontend/' + fileToLoad);
httpStatusCode = 404;
}
var fileBytes = fs.readFileSync('frontend/' + fileToLoad);
var mimeType = mimeTypes[path.extname(fileToLoad).split('.')[1]];
res.writeHead(httpStatusCode, {
'Content-type': mimeType
});
res.end(fileBytes);
});
// console.log("[INIT] Server running on HTTP Port");
}).listen(HTTP_PORT);
proxy.on("close", function(){
console.log("Connection has closed");
});
proxy.on("end", function(){
console.log("Connection has ended");
});
var socket;
var clients = [];
var socketObject;
var server = net.createServer(function (socket) {
socketObject = socket;
socket.name = socket.remoteAddress + ":" + socket.remotePort;
clients.push(socket);
console.log(socket);
socket.write("HTTP/1.1 101", function () {
console.log('[CONN] New connection: ' + socket.name + ', total clients: ' + clients.length);
});
socket.setEncoding('utf8');
socket.on('error', function (data) {
console.log(data);
});
socket.on('end', function () {
console.log('[END] Disconnection: ' + socket.name + ', total clients: ' + clients.length);
});
socket.on('data', function (data) {
console.log('[RECV from ' + socket.remoteAddress + "] " + data);
oldValue = newValue;
newValue = data;
diff = Math.abs(newValue) - Math.abs(oldValue);
console.log(Math.abs(newValue) + '-' + Math.abs(oldValue));
message.data = Math.abs(diff);
console.log('[SAVED] ' + message.data);
});
});
server.listen(NET_PORT, function () {
console.log("[INIT] Server running on NET server port", NET_PORT);
});
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({
port: WS_PORT
});
wss.on('connection', function (ws) {
// ws.send(JSON.stringify(message));
setInterval(function () {
updateXData(ws)
}, 500);
});
function updateXData(ws) {
var newMessage = {
"data": ""
}
newMessage.data = message.data
ws.send(JSON.stringify(newMessage));
}
So the question is: Is there a cleaner way to do this just by using ws to handle the data from the WiFly and then sending it to the client?
Thanks in advance!
Not sure whether this will suit you and might be new to you but you could make use of MQTT, there are free brokers available which are very good and its relatively easy to set up and implement with Arduino equipped with WiFly Shield.
http://mqtt.org/
Hope this helps somewhat!

How to create a node js server socket to receive data in different ports?

I need a socket server that must receive data from 100 clientes in different ports on the server. I've created an array of server sockets and I don't know if this is correct.
I also identified a slowness to receive the data when I have about 100 clients sending data and for some reason the server stops receiving from 10 clients.
Here is my code for 3 ports as an example.
var net = require('net');
var rl = require('readline');
var fs = require('fs');
var ports = [60001, 60002, 60003];
var server = new Array();
ports.forEach(function(value) {
server[value] = net.createServer(function (socket) { // array of socket servers
socket.on('error', function(err) {
console.log(err.stack);
server[value].close();
server[value].listen(value); //start listen again
});
socket.on('end', function() {
console.log('client disconnected: ' + value);
server[value].close();
server[value].listen(value); //start listen again
});
console.log('client connected: ' + value);
var intf = rl.createInterface(socket, socket);
intf.on('line', function (line) {
fs.exists(__dirname + "\\file" + value.toString() + ".txt", function (exists) {
if(exists){
var stream = fs.createWriteStream(__dirname + "\\file" + value.toString() + ".txt", {'flags': 'a'});
} else {
var stream = fs.createWriteStream(__dirname + "\\file" + value.toString() + ".txt", {'flags': 'w'});
}
try {
stream.once('open', function(fd) {
console.log(value.toString() + " - " + line);
stream.write(line + "\r\n");
stream.end();
});
} catch (x) {
console.log(x.stack);
}
});
});
});
server[value].listen(value); // listen many ports
});

how to concatenate buffer.toString() output with another string in Node.js

I'm using a simple socket script to establish an rcon connection to my Battlefield heroes server. I need to grab the seed from the returned data then concatenate it with the password to use in creating the login hash I need. But the strings won't concatenate with the normal string methods. If I output the strings separately they display fine, but they simply won't combine so I can hash them.
var net = require('net');
var crypto = require('crypto');
var md5sum = crypto.createHash('md5');
var HOST = '<ip address>', PORT = <port>,
PASSWORD = '<password>';
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
});
client.on('data', function(data) {
console.log(data.toString());
response = data.toString();
if (data.toString().slice(0,10) == "### Digest") {
var seed = response.slice(17);
auth = seed.concat(PASSWORD);
console.log('auth: '+auth);
hash = require('crypto').createHash('md5').update(auth).digest("hex");
console.log(hash);
//client.write('login '+hash+' \n');
}
//client.destroy();
});
client.on('close', function() {
//do something on close
});
client.on('error', function(err) {
console.log(err);
});
I found a solution that works for me. Not sure if I'm over doing it but I decided to pass both strings to new buffers. Then I passed them into an array to combine them. (shrug) I think it'll do. Any better solutions?
var net = require('net');
var crypto = require('crypto');
var md5sum = crypto.createHash('md5');
var HOST = '<ip address>', PORT = <port>,
PASSWORD = '<password>';
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
});
client.on('data', function(data) {
console.log(data.toString());
response = data.toString();
if (data.toString().slice(0,10) == "### Digest") {
var a = new Buffer(response.slice(17));
var b = new Buffer(PASSWORD);
var auth = new Array();
auth += a.toString().replace(/\n/g,'');
auth += b.toString();
hash = require('crypto').createHash('md5').update(auth).digest("hex");
client.write('login '+hash+' \n');
}
//client.destroy();
});
client.on('close', function() {
//do something on close
});
client.on('error', function(err) {
console.log(err);
});

socket.io RAM usage goes up over time

What can I do to keep ram at a reasonable level?
Before i start the server I have about 140mb ram free.
After 16 hours i have about 4mb free ram left.
I'm running this on a rackspace cloud with 256mb ram.
var maxMsgs = 50;
var express = require('express'), sio = require('socket.io'), redis = require('redis'), RedisStore = require('socket.io/lib/stores/redis');
var app = express.createServer(), pub = redis.createClient(), sub = redis.createClient(), client = redis.createClient();
app.configure(function () {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.static(__dirname + '/public'));
app.use(app.router);
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
app.listen(8002, function () {
var addr = app.address();
console.log('app listening on http://' + addr.address + ':' + addr.port);
});
var io = sio.listen(app, {log: false}), nicknames = {}, history = [], user_count = 0, topic = {topic: '', setBy: 'Server'}, ytvid = {vid: '', setBy: 'Server'};
io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('store', new RedisStore({redisPub : pub, redisSub : sub, redisClient : client}));
//io.set('resource', 'socket');
io.sockets.on('connection', function(socket) {
socket.on('join', function(cu) {
if(cu.username && cu.username != 'Guest') {
socket.nickname = cu.username;
socket.emit('connected', nicknames, history, topic, ytvid);
nicknames[cu.username] = cu;
socket.broadcast.emit('nicknames', nicknames);
user_count++;
//socket.broadcast.emit('announcement', {msg: socket.nickname + ' connected'});
}
});
socket.on('message', function(msg, cb) {
if(msg.msg && msg.msg != '') {
msg.time = Date.now() / 1000;
history.push(msg);
while(history.length > maxMsgs) history.shift();
cb(true, msg.time);
socket.broadcast.emit('message', msg);
}
});
socket.on('stopic', function(t) {
if(t.topic && t.setBy && t.topic != '') {
topic = t;
io.sockets.emit('topic', t);
} else {
topic = {topic: 'No topic set', setBy: 'Admin'};
io.sockets.emit('topic', topic);
}
});
socket.on('sytvid', function(v) {
if(v.vid && v.setBy && v.vid != '') {
ytvid = v;
io.sockets.emit('ytvid', v);
} else {
ytvid = {vid: false, setBy: 'Admin'};
io.sockets.emit('ytvid', ytvid);
}
});
socket.on('get debug', function() {
socket.emit('debug', {users: nicknames, history: history, user_count: user_count, topic: topic});
});
socket.on('send command', function(c) {
if(c.type == 'empty') history = [];
io.sockets.emit('command', c);
});
socket.on('disconnect', function() {
if(!socket.nickname) return;
if(!nicknames[socket.nickname]) return;
//nicknames[socket.nickname].status = 'offline';
delete nicknames[socket.nickname];
//socket.broadcast.emit('announcement', {msg: socket.nickname + ' disconnected'});
socket.broadcast.emit('nicknames', nicknames);
user_count--;
});
});
function inArray(needle,haystack){for(var key in haystack){if(needle===haystack[key]){return true;}}return false;}
function zeroPad(digits,n){n=n.toString();while(n.length<digits){n='0'+n;}return n;}
function time(time){if(time==null)time=new Date();else if((time instanceof Date)===false)time=new Date(time);return time;}
Looks like problem in socket.on('join') point.
I recommend you to start using
var profiler = require('v8-profiler');
setInterval(function() {
profiler.takeSnapshot('snappy');
},1000);
like described here http://code.google.com/p/v8/wiki/V8Profiler
So you will now where is your leak starts.
Also carefully check allocation and deallocation of each variable, object and scope.
Let me know if you have questions.
Some people think that socket.io leaks memory when using websockets transport. Try to disable it. Something along the lines of:
io.configure('production', function(){
io.enable('browser client etag');
io.set('log level', 1);
io.set('transports', [
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
});
Also heroku has to say the following

Resources