Socket.IO - setInverval every two minutes (Node JS) - node.js

I have an event in socket.io which broadcasts how many users are online (based on who is logged in) to the user.
What I think should be happening is that I ask the server to query the database once every two minutes using setInterval, and a rowset is returned, then emitted to the client.
What is happening though, is that for each user connected to the socket, it is calling the database on the server and pushing to the client.
I'm uncertain why this is doing this - I'd understand if I was asking it to do this from the client, but as it's the server emitting the event to the client, why would it be doing this several time for each user connected?
Thanks
io.on("connection", function(socket) {
// Update online users' every two minutes
setInterval(function() {
var roomNum = 0;
var outObj = {};
model.get_online_users(function(err, rowset) {
// Loop thorugh the rowset, set the roomNum and built up out_obj to output
io.to("room_number:"+roomNum).emit("online-users", outObj);
}); // End `model callback`
}, 120000); // End `get_online_users`
}); // End `io.on("connection")`

The code in io.on("connection", function(socket) { something(); }); is called for EVERY connected user, if you put a loop in this, the loop will loop paralelly for every connected user.
The setInterval should be outside of your io.on("connection", function(socket) { });, and it will run once, from your node server starting to the shutdown of the server.
Example :
setInterval(function() {
var roomNum = 0;
var outObj = {};
model.get_online_users(function(err, rowset) {
io.to("room_number:"+roomNum).emit("online-users", outObj);
});
}, 120000);

Related

Run multiple socket.io-clients in one node.js instance

I want to run stress tests using node.js, socket.io, and socket.io-client.
I want to get the network bandwidth, processor/memory use, etc.
I have a node.js socket.io server on amazon, size XLARGE.
Now I want to run multiple socket.io-clients in other amazon servers, and connect them to my server.
I was running it in different processes, but one node.js process takes 15MB memory. I want to test 100k socket.io connections simultaneously, so this is not an option.
My question is: Can I run, for example, 60k different socket.io-clients in one node.js instance?
This is my client code:
var socket = require('socket.io-client')('http://someAddress:3000');
socket.on('connect', function(){
socket.on('news', function(data){
});
socket.emit('event', { data: "Connection test." });
});
You have to pass forceNew option:
var socket = require('socket.io-client')('http://someAddress:3000', {
forceNew: true
});
And then initialize your sockets in a loop.
Here is a full test example:
server.js:
var io = require('socket.io')();
io.on('connection', function(socket){
var i = 0;
setInterval(function() {
socket.emit('news', {
message: i++
});
}, 1000);
});
io.listen(3000);
client,js:
function testOne() {
var socket = require('socket.io-client')('http://127.0.0.1:3000', {forceNew: true});
socket.on('connect', function(){
socket.on('news', function(data){
console.log(data.message);
});
});
}
for (var i = 0; i < 5; i++) {
testOne();
}
For testing purpose I've made client to output incrementing number for five times each second.

node.js application suddenly loads CPU at 100% and hangs

I have simple application on node.js running on linux virtual machine. It listens for tcp messages and sending them to the clients using socket.io library. And after some time of low CPU usage it suddenly starts to load CPU higher and higher until application hangs up. The script is simple and I can not understand what's wrong with it.
var net = require('net');
var io = require('socket.io').listen(socketPort);
net.createServer(function (socket) {
socket.setEncoding("utf8");
socket.on('data', function (dataStr) {
console.log("TCP dataStr " + dataStr);
var data = JSON.parse(dataStr);
io.sockets.in(data.room).emit('publish', data);
});
}).listen(tcpPort);
io.sockets.on('connection', function (socket) {
socket.on('subscribe', function (room) {
console.log('subscribe room ' + room);
if (Array.isArray(room)) {
var i;
for (i = 0; i < room.length; i++) {
console.log('subscribe join room ' + room[i]);
socket.join(room[i]);
}
} else if (typeof room === 'string') {
console.log('subscribe join room ' + room);
socket.join(room);
}
});
socket.on('unsubscribe', function (room) {
console.log('unsubscribe room ' + room);
if (Array.isArray(room)) {
var i;
for (i = 0; i < room.length; i++) {
console.log('unsubscribe leave room ' + room[i]);
socket.leave(room[i]);
}
} else if (typeof room === 'string') {
console.log('unsubscribe leave room ' + room);
socket.leave(room);
}
});
});
Also with cluster module I tried to run multiple workers that communicate with clients. And every worker after some time hangs own CPU core at 100% with time difference in about a minute.
UPD: Client code (run in browser):
socketObj = new function() {
var that = this;
that.socket;
that.init = function(nodeServerUrl, rooms, onPublishFunc) {
that.socket = io.connect(nodeServerUrl);
that.socket.emit('subscribe', rooms);
that.socket.on('publish', function(data) {
onPublishFunc(data);
});
};
that.subscribe = function(room) {
that.socket.emit('subscribe', room);
};
that.unsubscribe = function(room) {
that.socket.emit('unsubscribe', room);
};
}
...
try {
socketObj.init('application url', ["room1", "room2"], nodeJsCallback);
} catch(err) {
}
...
nodeJsCallback = function(jsonData) {
//Only updates data on UI, no subscribing, unsubscribing, emitting etc.
...
}
UPD2: I tried to reproduce the problem with synthetic tests on production machine and on my local Windows machine. I have done some stress testing:
Multiple client socket connections
Multiple static data downloads (socket.io script for browser)
Increased frequence of tcp updates.
After few hours of testing I failed to reproduce. But when it is running on production with real users, it is hanging up earlier or later.
I'm starting to think this is either environment or specific message problem. Probably next things I'll try are:
Update Node.js to current version
Try to log all data transfer and replay it later hoping hanging will reproduce
Changed Nodejs from version v0.10.4(Stable) to v0.11.2(Unstable). All woking good so far, consuming 1-2% CPU. Now we are testing on v0.10.8(Stable).
UPD On v0.10.8 application is stable too.
Even though the problem dissapeared on v0.10.4(Stable), it is still very strange and discouraging.

Node.JS and Socket.io - Broadcast returns to sender

I am building a real-time web-application with multiple clients and a node.js server to handle state and broadcast event changes from clients. I have implemented Socket.io as transport mechanism between clients and server. When a client performs a specific action an event this is send to the server, which is broadcasted to other clients on the network.
However, sometimes when an array of events is recieved by the server, the server doesn't broadcast it but instead sends it back to the sending client - or sends it to all connected sockets including the sending client.
Here is a snippet of the server implementation, which basically listens for client events, collects them in an array which is broadcasted every 2 seconds.
If you want, I can include relevant snippets from the client implementation.
// Require HTTP module (to start server) and Socket.IO
var http = require('http'), io = require('socket.io'), users = require('./users');
// Commands to client
var USER_LOGIN = 0,
USER_LIST = 1,
USER_CONNECTED = 2,
USER_DISCONNECTED = 3,
COMMAND = 4,
COMMAND_SETNICKNAME = 0,
COMMAND_POSITION = 1,
COMMAND_MOUSEDOWN = 2,
var array = [];
var activeUsers = {};
// Start the server at port 8080
var server = http.createServer(function(req, res){
res.writeHead(200,{ 'Content-Type': 'text/html' });
});
server.listen(8080);
// Create a Socket.IO instance, passing it our server
var io = io.listen(server);
// Add a connect listener
io.sockets.on('connection', function(client){
console.log("started");
// Create periodical which ends a JSON message to the client every 2 seconds
var interval = setInterval(function() {
if(array.length >0) {
console.log("Sending to clients " + array);
//client.send(JSON.stringify(array));
client.broadcast.send(JSON.stringify(array));
array = [];
}
},2000);
// Success! Now listen to messages to be received
client.on('message',function(event){
console.log("--Reading event " + event);
var eventArray = JSON.parse(event);
for(var i = 0; i < eventArray.length; i++) {
var dataArray = eventArray[i];
var userId = parseInt(dataArray[0]);
var position = 1;
console.log("current element in array " + dataArray);
switch (parseInt(dataArray[position++])) {
case USER_LOGIN:
// Log in user with USERID.
var username = dataArray[position++];
console.log("Attempting to log in with user " + username);
// If valid, send USER_LOGIN broadcast to clients
if(login(username)) {
array.push([0, USER_LOGIN, login(username)]);
}
break;
io.sockets.on('connection', function(client){
console.log("started");
// Create periodical which ends a JSON message to the client every 2 seconds
var interval = setInterval(function() {
if(array.length >0) {
console.log("Sending to clients " + array);
//client.send(JSON.stringify(array));
client.broadcast.send(JSON.stringify(array));
array = [];
}
},2000);
you are creating one scheduler for each connection which is going to be a mess. Because you are creating the interval inside on('connection',
And I don't see any point of calling clients in an interval because you have a method to push the changes on some clients change event. That is the advantage of socket.io . Instead of using an interval you can just broadcast the change in another listener from client change event like this.
client.on('onSomechangeInClient',function(event){
//update array here..
client.broadcast.send(JSON.stringify(array));
});

node.js setInterval doesn't work

With node.js, I'm trying to send the current server_time to all clients in every second.
Therefore, I wanted to use setInterval() to emit an event to all clients and sending the time, but it doesn't work. Did I define the setInterval function at the right place or did missed something else?
var http = require("http");
var socketIO = require('socket.io');
var connect = require('connect');
//keep track of every connected client
var clients = {};
//create Server
var httpServer = connect.createServer(
connect.static(__dirname)
).listen(8888);
//socket
var io = socketIO.listen(httpServer);
io.sockets.on('connection', function (socket) {
//add current client id to array
clients[socket.id] = socket;
socket.on('close', function() {
delete clients[socket.fd]; // remove the client.
});
//send news on connection to client
socket.emit('news', { hello: 'world' });
//this one works fine!
//send server time on connection to client
socket.emit("server_time", { time: new Date().toString() });
});
//this doesn't work!
// Write the time to all clients every second.
setInterval(function() {
var i, sock;
for (i in clients) {
sock = clients[i];
if (sock.writable) { // in case it closed while we are iterating.
sock.emit("server_time", {
console.log("server_time sended");
time: new Date().toString()
});
}
}
}, 1000); //every second
May I suggest a workaround/improvement that should fix the problem. Add the clients to a chat room. Somewhere in:
io.sockets.on('connection', function (socket) {
add a
socket.join('timer');
Then the setIntervall would be
setInterval(function() {
io.sockets.in('timer').emit("server_time", { time: new Date().toString() })
}, 1000);
Hope this works for you!
The problem is the following function:
if (sock.writable) { // in case it closed while we are iterating.
sock.emit("server_time", {
// console.log("server_time sended"); // get rid of this line -> invalid code
time: new Date().toString()
});
}
sock.writable is undefined and therefore the emit event is never sent. Set the property to true on connection and to false on close.

Create a list of Connected Clients using socket.io

Here are 2 related questions. Posting them together makes more sense.
Question 1
I have a node.js app which emits an event out to all clients, and all current clients will respond with a ready emit. How can I create a list of all the clients that replied to the initial emit, and what kind of identification can be used to distinguish the clients?
Question2:
What I am trying to do after collect a list of connected clients, is to then access a MySQL database table of N number of rows and assign each client X rows each. These rows will be emitted back to their respective clients. How can this be done?
Current Code for Qn 1
Node Code
setInterval(function() {
util.log('Checking for new jobs...');
dbCheckQueue(function(results) { // checks if there are new rows to "distribute" to clients
if (results.length) {
util.log(results.length + ' new jobs found.');
io.sockets.emit('job_available');
}
});
}, 10*1000);
Client-side JS Code
socket.on('job_available', function() {
console.log('Job Available.. Responding with Ready!');
socket.emit('ready');
});
io.sockets.on('connection', function(socket) {
socket.on('ready', function() {
// UPDATE N rows with client_id in column checkout.
// Then SELECTS * from table where checkout = client_id
getListings(client_id, function(listings) {
socket.emit('job', listings); // send jobs
});
});
});
Current Code for Qn 2
The code works for a single client, but how do I loop through all connected clients and perform the same updating of column and selecting of rows?
io.sockets.on('connection', function(socket) {
socket.on('ready', function() {
// UPDATE N rows with client_id in column checkout.
// Then SELECTS * from table where checkout = client_id
getListings(client_id, function(listings) {
socket.emit('job', listings); // send jobs
});
});
});
Socket.io provides you with a public api for that, so instead of hacking something up like Bryan suggest you can use:
io.sockets.clients()
That will returns an array of all connected clients.
If you want all clients connected to a certain namespace:
io.of('/namespace').clients()
But you can even filter it even more.. if you want to have all sockets in a room:
io.sockets.clients('room name here as first argument')
Will return a array of connected sockets for the room room name here as first argument
You will need to keep track of the connected clients yourself. The simple way to do that would be to use an array:
var clients = [];
io.sockets.on('connect', function(client) {
clients.push(client);
client.on('disconnect', function() {
clients.splice(clients.indexOf(client), 1);
});
});
Then you can references that clients array on the server wherever you need to, in your ready event handler or whatever. Something like:
io.sockets.on('connection', function(socket) {
socket.on('ready', function() {
// UPDATE N rows with client_id in column checkout.
// Then SELECTS * from table where checkout = client_id
clients.forEach(function(client, index) {
var client_id = index; // Just use the index in the clients array for now
getListings(client_id, function(listings) {
socket.emit('job', listings); // send jobs
});
});
});
});

Resources