Nodejs server stop accept connections after a few hours - javascript

I made an application to the control of simultaneous logins, in starts everything works perfectly, however after a few hours i can not longer connect to the server, my client returns me the following error: net :: ERR_CONNECTION_TIMED_OUT and on the server side does not happen any error like it was running correctly... code below:
CLIENT SIDE:
var socket;
function connect(id) {
socket = io.connect('http://IP:4200');
socket.on('connect', function (data) {
socket.emit('join', id);
});
socket.on('messages', function (data) {
console.log('MSG: ' + data.toString());
switch (data.toString()) {
case "kick":
socket.close();
console.log("KICK!");
break;
case "duplicate_entry":
socket.close();
console.log("Another user connection!");
break;
}
});
}
SERVER SIDE:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var clients = [];
app.use(express.static(__dirname + '/bower_components'));
function logtimestamp() {
var log_date = new Date();
log_date = '[' + log_date.getFullYear() + '/' + (log_date.getMonth() + 1) + '/' + log_date.getDate() + ' ' + log_date.getHours() + ':' + log_date.getMinutes() + ':' + log_date.getSeconds() + ']';
return log_date;
}// FUNCTION logtimestamp
console.log("Start time: " + logtimestamp());
console.log("Server port 4200")
console.log("websocket server created!");
try {
io.on('connection', function (client) {
try {
var id;
var conexao;
client.on('join', function (data) {
try {
console.log('Client connected...'+logtimestamp()+' ID:' + data);
id = data;
conexao = {
ws: client,
id_user: data
};
clients.push(conexao);
for (var x = 0; x < clients.length; x++) {
//desconect previous user
try {
if (clients[x].id_user == id) {
if (clients[x].ws != conexao.ws) {
clients[x].ws.emit('messages', 'duplicate_entry');
clients.splice(x, 1);
}
}
} catch (err) {
console.log("ERROR 1: " + err.message);
}
}
} catch (err) {
console.log("ERROR 2: " + err.message);
}
});
} catch (err) {
console.log("ERROR 3: " + err.message);
}
});
} catch (err) {
console.log("ERROR 4: " + err.message);
}
server.listen(4200);

I see a couple possible issues. It is hard for us to know by just inspecting code which issues actually are the cause of your issue. In any case, you should clean up these issues and see if it improves the situation:
You should respond the the disconnect event and immediately remove any socket from your clients array when it disconnects.
In your loop where you are looking to removing any prior instances of a given user, your for loop will not work properly when you are doing .splice(x, 1) in the middle of the for loop. This will move all items after it does one in the array causing you to skip the comparison of the next element in the array. One simple way to get around this is to iterate the array backwards: for (var x = clients.length - 1; x >= 0; x--) because then the elements who's position are affected after the .splice() are elements you have already looked at. None will be missed.
Beyond this, you should examine the memory usage of the nodejs process, the open sockets by the nodejs process and the CPU usage of the nodejs process to see if any of those point to any possible issues.
And, what is your deployment environment? Is there a proxy server in front of your web server?

Related

Node JS TCP Server with simple password prompt problem

I'm trying to build a TCP server on node JS. The idea is to have multiple TCP clients connect and send / receive data(from server to client / client to server) and to have some sort of authentication (at least to enter a strong password) Also not sure if this approach is worth it. But, I've come up with something (most from online sources and docs) and crated below code.
Code runs and I can connect, but if I send data from client to server, the "password" check function fires up and each time I enter the correct password, a new (duplicate connection) is created. Seems like it keeps calling the same function on each input.
Desired behavior would be ; once client try's to connect, needs to provide the password and then start sending date. Also could someone give me a hint on how to send data back from server, or is it even possible. Or do I need to create a separate function for server.createConnection()
thanks in advance
UPDATE :I've changed the code a bit, but the main issue remains. this bit was supposed to check whether "clientAddress" exists and if so skip the auth part all together.
server.on('connection', (socket) => {
let clientAddress = `${socket.remoteAddress}:${socket.remotePort}`;
console.log(clientAddress)
if(sock.indexOf(clientAddress) !== -1){
console.log('devie found, opening communication')
newConnectionHandler(socket,clientAddress)
} else {
console.log('devie not found, need to authenticate')
userAuth(socket,clientAddress)
}
but as you can guess, it's not working :) if I manually specify the "clientAddress" it works , if I place "sock.push(clientAddress);" within the first block of code, it also works. No auth is asked. But when it's placed within
function userAuth(socket,clientAddress){
socket.write('password : ' )
socket.on('data', function (data) {
let pass = data.toString()
if (pass == password) {
sock.push(clientAddress);
console.log(sock)
newConnectionHandler(socket,clientAddress)
return;
} else {
//console.log(pass)
socket.write('Sorry, you cannot access the server \n')
console.log('acess denied for ' + socket.remoteAddress + ':' + socket.remotePort + '\n')
socket.write('connection closed')
socket.destroy()
}
})
}
code does run as expected and goes all the way till
function newConnectionHandler(socket,clientAddress){
//console.log(sock)
socket.write('Welcome \n')
socket.on('data', function(data1){
console.log("Client Sent: " + data1);
});
but as soon as I send a new message from the client, it goes back as if it was never authenticated and treats my input as the password and because it does not match with the actual password,it destroys the connection.
can someone please give me a hand...
const net = require('net');
const port = 3001;
const host = '192.168.0.165';
const server = net.createServer()
let sock = [];
let password = 123
//server.on('listening',createConnection);
server.on('connection', (socket) => {
let clientAddress = `${socket.remoteAddress}:${socket.remotePort}`;
console.log(clientAddress)
if(sock.indexOf(clientAddress) !== -1){
console.log('devie found, opening communication')
newConnectionHandler(socket,clientAddress)
} else {
console.log('devie not found, need to authenticate')
userAuth(socket,clientAddress)
}
server.on('error', errorHandler);
function errorHandler(err){
console.log(`Error occurred in ${clientAddress}: ${err.message}`);
}
function userAuth(socket,clientAddress){
socket.write('password : ' )
socket.on('data', function (data) {
let pass = data.toString()
if (pass == password) {
sock.push(clientAddress);
console.log(sock)
newConnectionHandler(socket,clientAddress)
return;
} else {
//console.log(pass)
socket.write('Sorry, you cannot access the server \n')
console.log('acess denied for ' + socket.remoteAddress + ':' + socket.remotePort + '\n')
socket.write('connection closed')
socket.destroy()
}
})
}
function newConnectionHandler(socket,clientAddress){
//console.log(sock)
socket.write('Welcome \n')
socket.on('data', function(data1){
console.log("Client Sent: " + data1);
});
socket.once('close', (data) => {
let index = sock.findIndex((o) => {
return o.remoteAddress === socket.remoteAddress && o.remotePort === socket.remotePort;
})
if (index !== -1) sock.splice(index, 1);
sock.forEach((sock) => {
socket.write(`${clientAddress} disconnected\n`);
        });
console.log(`connection closed: ${clientAddress}`);
    });
}
/* function createConnection(){
// Start a connection to the server
var socket = server.on('connect',function(){
// Send the initial message once connected
socket.write({question: "Hello, world?"});
});
// Whenever the server sends us an object...
socket.on('data', function(data){
// Output the answer property of the server's message to the console
console.log("Server's answer: " + data.answer);
});
} */
})
server.listen(port, host, () => {
console.log('TCP Server is running on port ' + port + '.');
});
so it appears as the only bit of code that was causing the authentication loop was the
function userAuth(socket,clientAddress){
socket.write('password : ' )
**socket.on('data', function (data) {**
let pass = data.toString()
after changing "on" with "once" it is now functioning properly. I tested with two TCP clients, both connected and was asked to enter a password. They can both actively send messages to the server and both disconnected properly in the end.
this is the code if anyone finds any use for it :) the connection it's self is still unencrypted so not good for sending/receiving sensitive data.
const net = require('net');
const port = 3001;
const host = '192.168.0.165';
const server = net.createServer()
let sock = [];
let password = 123
//server.on('listening',createConnection);
server.on('connection', (socket) => {
let clientAddress = `${socket.remoteAddress}:${socket.remotePort}`;
console.log(clientAddress)
if(sock.indexOf(clientAddress) !== -1){
console.log('devie found, opening communication')
newConnectionHandler(socket,clientAddress)
} else {
console.log('devie not found, need to authenticate')
userAuth(socket,clientAddress)
}
})
server.on('error', errorHandler);
function errorHandler(err){
console.log(`Error occurred in ${clientAddress}: ${err.message}`);
}
function userAuth(socket,clientAddress){
socket.write('password : ' )
socket.once('data', function (data) {
let pass = data.toString()
if (pass == password) {
sock.push(clientAddress);
console.log(sock)
newConnectionHandler(socket,clientAddress)
return;
} else {
//console.log(pass)
socket.write('Sorry, you cannot access the server \n')
console.log('acess denied for ' + socket.remoteAddress + ':' + socket.remotePort + '\n')
socket.write('connection closed')
socket.destroy()
}
})
}
function newConnectionHandler(socket,clientAddress){
//console.log(sock)
socket.write('Welcome \n')
socket.on('data', function(data1){
console.log("Client Sent: " + data1);
});
socket.on('close', function(data) {
let index = sock.findIndex(function(o) {
return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort;
})
if (index !== -1) sock.splice(index, 1);
console.log('CLOSED: ' + socket.remoteAddress + ' ' + socket.remotePort);
});
}
/* function createConnection(){
// Start a connection to the server
var socket = server.on('connect',function(){
// Send the initial message once connected
socket.write({question: "Hello, world?"});
});
// Whenever the server sends us an object...
socket.on('data', function(data){
// Output the answer property of the server's message to the console
console.log("Server's answer: " + data.answer);
});
} */
server.listen(port, host, () => {
console.log('TCP Server is running on port ' + port + '.');
});

Node.js broadcasting twice

I'm giving my first steps with node.js. I'm trying to implement a simple chat room to get the basics, but can't figure out why after every broadcast, a second (empty) message is automatically sent. This behaviour happens most of the time but not always. I'm using Netbeans in Windows, with Putty to simulate the client connections.
Console output:
Server running
::1:60616 joined
::1:60617 joined
-----------
Broadcasting:
hello
-----------
Broadcasting:
-----------
Broadcasting:
goodbye
-----------
Broadcasting:
-----------
Client 1:
Hi ::1:60616!
hello
goodbye
Client 2:
Hi ::1:60617!
::1:60616 says hello::1:60616 says
::1:60616 says goodbye::1:60616 says
Code
var net = require('net');
var chatServer = net.createServer();
var clientList = [];
console.log('Server running');
chatServer.on('connection', function (client) {
client.name = client.remoteAddress + ':' + client.remotePort;
client.write('Hi ' + client.name + '!\n');
console.log(client.name + ' joined');
clientList.push(client);
client.on('data', function (data) {
console.log('Broadcasting: ');
console.log(data.toString());
console.log('-----------');
broadcast(data, client);
});
client.on('end', function () {
console.log(client.name + ' quit');
clientList.splice(clientList.indexOf(client), 1);
});
client.on('error', function (e) {
console.log(e);
});
});
function broadcast(message, sender) {
var text = sender.name + " says " + message;
var cleanup = [];
clientList.forEach(function (client) {
if (client !== sender) {
if (client.writable) {
client.write(text);
} else {
cleanup.push(client);
client.destroy();
}
}
});
cleanup.forEach(function (client) {
clientList.splice(clientList.indexOf(client), 1);
});
}
chatServer.listen(9000);
You can't rely on the raw data event to present you with "well-rounded" chunks of data. It may come in pieces, and you can't necessarily control how large those pieces are, or that they get split on particular boundaries.
However, there are modules that can help you, for instance split, which will split the data into separate (full) lines:
const split = require('split');
...
client.pipe(split()).on('data', function (data) {
// `data` is now a separate line
console.log('Broadcasting: ');
console.log(data.toString());
console.log('-----------');
broadcast(data, client);
});

node.js / socket.io - keep track of clients

Dear friends I have a small issue while trying to keep track of a logged in users in chat. The chat is based on two separate channels that work with the help of namespaces:
chatInfra - to handle logged in users and send welcome messages.
chatCom - to handle messageing between users.
I have searched a lot but I found only theoretical explanations that the best solutions is to store users into array. Therefore I tried to keep the track of logged in users by storing them in array and then iterating through them but still the result is not good.
The problem is that after entering to the chat, only the first logged in user's name appears on screen, whereas the second user's name is not visible.
This is my server side code, I am trying to store users into clients array:
var clients = [];
var chatInfra = io.of("/chat_infra").on("connection", function(socket){
socket.on("set_name", function (data) {
clients.push(data.name);
socket.emit('name_set', data);
socket.send(JSON.stringify({
type:'serverMessage',
message:'Welcome!'
}));
socket.broadcast.emit('user_entered', data);
});
});
var chatCom = io.of("/chat_com").on("connection", function (socket) {
socket.on('message', function (message) {
message = JSON.parse(message);
for(var key in clients){
if(message.type == "userMessage"){
message.username = clients[key];
console.log('message : ', message);
socket.broadcast.send(JSON.stringify(message));
message.type = "myMessage";
socket.send(JSON.stringify(message));
}
}
});
});
Here is how it looks in browser: http://screencast.com/t/lshnfcGZ8E8
Here is the full code: https://gist.github.com/johannesMatevosyan/0b9f7e588338dbb6b7f5
I think you're creating an unnecessary overkill by using different namespaces. Here's a clearer working example achieving the same functionality:
server.js
var app = require("express")();
var server = require("http").Server(app);
var io = require("socket.io")(server);
var chat = io.of("/chat").on("connection", function(socket){
socket.on("set_name", function (data) {
socket.username = data.name;
socket.emit("name_set", data);
socket.emit("message", {
type :"serverMessage",
message :"Welcome!"
});
chat.emit("message", {
type :"serverMessage",
message : data.name + " has joined the room.!"
});
});
socket.on("message", function (message) {
message.username = socket.username;
chat.emit("message", message);
});
});
app.get("/", function (req, res) {
res.sendfile(__dirname + "/index.html");
});
server.listen(3000);
client.js
var socket = io.connect('http://localhost:3000/chat');
socket.on('name_set', function (data) {
$('#nameform').hide();
$('#messages').append('<div class="systemMessage">Hello ' + data.name + '</div>');
});
socket.on('message', function (message) {
var userNameHtml = message.username ? '<span class="name">' + message.username + ':</span>' : '';
$('#messages').append('<div class="' + message.type + '">' + userNameHtml + message.message + '</div>');
});
$(function () {
$('#setname').click(function () {
socket.emit("set_name", { name: $('#nickname').val() });
});
$('#send').click(function () {
socket.emit("message", {
message : $('#message').val(),
type : 'userMessage'
});
$('#message').val('');
});
});
I don't think you need a separate event handler for user_entered, since you are treating it as a regular message and not doing anything else with the event. Also a couple of things:
You don't need to first connect to the server and then to the namespace address, connecting to the later is just fine.
Don't set event listeners within callbacks, that will result in setting them multiple times.

Duplicate Events Socket.io and Node.js over STOMP

I need some help about my node.js+socket.io implementation.
This service expose a server that connects to an ActiveMQ broker over the STOMP protocol, using the stomp-js node.js module to receive events; that then are displayed in a web front end through websockets using socket.io.
So, everything was fine until I started use the Filters feature of ActiveMQ, but this was not the failure point because of my and my team researching, we found the way to ensure the implementation was fine, the problem comes with the connections: So here's the thing, I receive the filters to subscribe, I successfully subscribe to but when I receive a new set of filters is when comes the duplicated, triplicated and more and more messages depending the number of times that I subscribe-unsubscribe to.
So making some debug, I cannot see what's the problem but I'm almost sure that is some bad implementation of the callbacks or the program flow, I'll attach my code to read your comments about it.
Thanks a lot!
var sys = require('util');
var stomp = require('stomp');
var io = require('socket.io').listen(3000);
var socket = io.sockets.on('connection', function (socket) {
var stomp_args = {
port: 61616,
host: 'IP.ADDRESS',
debug: true,
};
var headers;
var client = new stomp.Stomp(stomp_args);
var setFilters = false;
socket.on('filtros', function (message) {
console.log('DEBUG: Getting filters');
if(setFilters){
client.unsubscribe(headers);
}
else{
client.connect();
}
var selector = '';
headers = '';
for(var attributename in message){
console.log(attributename+" : " + message[attributename]);
if(message[attributename] != ''){
selector += ' ' + attributename + '=\'' + message[attributename] + '\' AND ';
}
}
selector = selector.substring(0, selector.length - 4)
console.log('DEBUG: Selector String: ' + selector);
headers = {
destination: '/topic/virtualtopic',
ack: 'client',
selector: selector
};
if(setFilters)
client.subscribe(headers);
client.on('connected', function() {
client.subscribe(headers);
console.log('DEBUG: Client Connected');
setFilters = true;
});
});
var bufferMessage;
client.on('message', function(message) {
console.log("Got message: " + message.headers['message-id']);
var jsonMessage = JSON.parse(message.body);
if(bufferMessage === jsonMessage){
console.log('DEBUG: recibo un mensaje repetido');
return 0;
}
else{
console.log('DEBUG: Cool');
socket.emit('eventoCajero', jsonMessage);
}
client.ack(message.headers['message-id']);
bufferMessage = jsonMessage;
});
socket.on('disconnect', function(){
console.log('DEBUG: Client disconnected');
if(setFilters){
console.log('DEBUG: Consumer disconnected');
client.disconnect();
}
});
client.on('error', function(error_frame) {
console.log(error_frame.body);
});
});
Looking in the Socket.IO documentation, I've found that this is a known issue (I think critical known issue) and they have not fixed it yet. So, to correct this is necessary to reconnect to the socket in the client side to avoid duplicate messages, using:
socket.socket.reconnect();
function to force reconnection explicitly.

Memory Leak with socket.io + node.js

I appear to have a memory leak with my Node.js application. I built it quickly, and my JavaScript isn't too strong, so this might be easy.
I've done some heap dumps on it, and it's the String object? leaking memory, at the rate of about 1MB every 5 minutes. I expanded String, and it's actually String.Array?
Heap stack:
#!/usr/local/bin/node
var port = 8081;
var io = require('socket.io').listen(port),
sys = require('sys'),
daemon = require('daemon'),
mysql = require('mysql-libmysqlclient');
var updateq = "SELECT 1=1";
var countq = "SELECT 2=2";
io.set('log level', 2);
process.on('uncaughtException', function(err) {
console.log(err);
});
var connections = 0;
var conn = mysql.createConnectionSync();
dbconnect();
io.sockets.on('connection', function(client){
connections++;
client.on('disconnect', function(){ connections--; })
});
process.on('exit', function () {
console.log('Exiting');
dbdisconnect();
});
function dbdisconnect() {
conn.closeSync();
}
function dbconnect() {
conn.connectSync('leet.hacker.org','user','password');
}
function update() {
if (connections == 0)
return;
conn.query(updateq, function (err, res) {
if (err) {
dbdisconnect();
dbconnect();
return;
}
res.fetchAll(function (err, rows) {
if (err) {
throw err;
}
io.sockets.json.send(rows);
});
});
}
function totals() {
if (connections == 0)
return;
conn.query(countq, function (err, res) {
if (err) {
// Chances are that the server has just disconnected, lets try reconnecting
dbdisconnect();
dbconnect();
throw err;
}
res.fetchAll(function (err, rows) {
if (err) {
throw err;
}
io.sockets.json.send(rows);
});
});
}
setInterval(update, 250);
setInterval(totals,1000);
setInterval(function() {
console.log("Number of connections: " + connections);
},1800000);
daemon.daemonize('/var/log/epiclog.log', '/var/run/mything.pid', function (err, pid) {
// We are now in the daemon process
if (err) return sys.puts('Error starting daemon: ' + err);
sys.puts('Daemon started successfully with pid: ' + pid);
});
Current version
function totals() {
if (connections > 0)
{
var q = "SELECT query FROM table";
db.query(q, function (err, results, fields) {
if (err) {
console.error(err);
return false;
}
for (var row in results)
{
io.sockets.send("{ ID: '" + results[row].ID + "', event: '" + results[row].event + "', free: '" + results[row].free + "', total: '" + results[row].total + "', state: '" + results[row]$
row = null;
}
results = null;
fields = null;
err = null;
q = null;
});
}
}
Still leaking memory, but it seems only on these conditions:
From startup, with no clients -> Fine
1st client connection -> Fine
2nd client (even with the 1st client disconnecting and reconnecting) -> Leaking memory
Stop all connections -> Fine
1 new connection (connections = 1) -> Leaking memory
Do yourself a favour and use node-mysql, it's a pure javascript mysql client and it's fast. Other than that, you should be using asynchronous code to stop IO being blocked whilst you're working. Using the async library will help you here. It has code for waterfall callback passing among other things.
As for your memory leaking, it probably isn't socket.io, although I haven't used it in a few months, I have had many thousands of concurrent connections and not leaked memory, and my code wasn't the best either.
Two things, however. Firstly your code is faily unreadable. I suggest looking into properly formatting your code (I use two spaces for every indentation but some people use four). Secondly, printing the number of connections every half an hour seems a little silly, when you could do something like:
setInterval(function() {
process.stdout.write('Current connections: ' + connections + ' \r');
}, 1000);
The \r will cause the line to be read back to the start of the line and overwrite the characters there, which will replace the line and not create a huge amount of scrollback. This will help with debugging if you choose to put debugging details in your logging.
You can also use process.memoryUsage() for quickly checking the memory usage (or how much node thinks you're using).
Could this be related to the connected clients array not clearing properly when a client disconnects? The array value gets set to NULL rather than being dropped from the array.

Categories