My nodejs server under heavy load for some reason, all i'm running is a small app using socket io. This app mainly gets text from a textarea on an html page and updates it to the people in the "room". Sort of like a live chat. However this is causing huge load on my server every time someone types something if theres 2 clients per room it will cause a lag spike.
server-side code
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');
app.listen(process.env.PORT);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.on('connection', function (socket) {
socket.on('join_room',function(room){
socket.join(room);
socket.in(room).emit('joined_room', 'true');
});
socket.on('blob', function (room) {
socket.in(room.name).emit('new_text', room.update_text);
});
socket.on('blob-typing',function(room){
socket.in(room.name).emit('some_typing', {cur_loc:room.cursor_location});
});
});
client-side code
var socket = io.connect('x');
socket.emit('join_room',url_key);
setInterval(function(){
if (field_change === true) {
var post_data = {
name: url_key,
update_text: $('.blob').val()
};
socket.emit('blob', post_data);
post_data = {
name: url_key,
cursor_location:0
};
socket.emit('blob-typing', post_data);
}
field_change = false;
},1000);
$(".blob").on('keyup paste input',function () {
delay(function(){
field_change = true;
},500);
});
socket.on('joined_room',function(data){
});
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
Please advise as to how i can fix the load, any technique or strategy would be much appreciated!
Related
Hello I'm trying to create a chat application, I googled around and I got some issues on this step. Would appreciate some help...
Server.js
var express = require("express");
var app = express();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
var users = [];
io.on("connection", function (socket) {
console.log("User connected", socket.id);
socket.on("user_connected", function (username) {
users[username] = socket.id;
io.emit("user_connected", username);
});
socket.on("send_message", function (data) {
var socketId = users[data];
io.to(socketId).emit("new_message", data);
console.log(data);
});
});
http.listen(3000, function () {
console.log("Server Started");
});
chat.php
function sendMessage(){
var message = document.getElementById("message").value;
io.emit("send_message", {
sender: sender,
message: message
});
return false;
}
io.on("new_message", function (data) {
console.log(data);
//var html = "";
//html += "<li>" + data.sender + " says: " + data.message + "</li>";
//document.getElementById("messages").innerHTML += html;
});
So my problem is happening in chat.php where my console.log(data) isn't shown, however the data is shown in server.js. Why is this currently not working?
From what you said earlier it's possible that you make it more complicated than it actually is. No need to change anything in chat.php, however instead of creating the variable socketId you could just emit the data immediately like this:
io.on("connection", function (socket) {
console.log("User connected", socket.id);
socket.on("user_connected", function (username) {
users[username] = socket.id;
io.emit("user_connected", username);
});
socket.on("send_message", function (data) {
io.emit("new_message", data);
});
});
I am trying to execute few python script inside nodejs. The code is shown below. What I am trying to do is executing different python script inside a for loop one by one. and send the json response to client as soon as one script gets over.
var PythonShell = require('python-shell');
var express = require('express'), app = express();
app.get('/', function (req, res) {
res.setHeader('Content-Type', 'text/html');
pl_list=["test", "test2"]
for (var i=0; i<= pl_list.length-1; i++) {
output="";
var pyshell = new PythonShell('./'+pl_list[i]+'.py')
pyshell.on('message', function (message)
{console.log(message);output+=message;});
pyshell.end(function (err) {
if (err){
console.log('error occured ---- '+err);
}
else{
console.log('update finished');
res.write(JSON.stringify({"finsihed":true, "product_line":pl_list[i]}));
}
});
}
//res.end()
});
app.listen(5000, function () {
console.log('The web server is running. Please open http://localhost:5000/ in your browser.');
});
unfortunately I am getting the response as {"finsihed":true} actual output must be
{"finsihed":true, "product_line":"test"}{"finsihed":true, "product_line":"test2"}
can anybody tell me what I am doing wrong here. Thanks in advance!
The execution of your python scripts is asynchronous, so when you write the response to the client with this line, the value of i changed:
res.write(JSON.stringify({"finsihed":true, "product_line":pl_list[i]})
Just display the value of i with console.log before the above line and you will see that i equals 2 twice (due to the increment of your for-loop). And because pl_list[i] is undefined, the serialization of a JSON object removes the attribute "product_line".
If you want to "save" the value of i, you have to learn what closure is.
This code should work:
var PythonShell = require('python-shell');
var express = require('express'),
app = express();
app.get('/', function (req, res) {
res.setHeader('Content-Type', 'text/html');
var nbFinishedScripts = 0;
pl_list = ["test", "test2"]
for (var i = 0; i <= pl_list.length - 1; i++) {
output = "";
var pyshell = new PythonShell('./' + pl_list[i] + '.py')
pyshell.on('message', function (message)
{
console.log(message);
output += message;
});
// closure
(function (i) {
return function () {
pyshell.end(function (err) {
if (err) {
console.log('error occured ---- ' + err);
} else {
console.log('update finished');
res.write(JSON.stringify({
"finsihed": true,
"product_line": pl_list[i]
}));
}
nbFinishedScripts++;
// end the reponse when the number of finished scripts is equal to the number of scripts
if (nbFinishedScripts === pl_list.length) {
res.end();
}
});
};
})(i)(); // immediately invoke the function
}
});
app.listen(5000, function () {
console.log('The web server is running. Please open http://localhost:5000/ in your browser.');
});
Edit code:
var PythonShell = require('python-shell');
var express = require('express'),
app = express();
var executePythonScript = function (script) {
return new Promise(function (resolve, reject) {
var pyshell = new PythonShell('./' + script + '.py');
pyshell.end(function (err) {
if (err) {
reject(err);
} else {
resolve(script);
}
});
});
};
app.get('/', function (req, res) {
res.setHeader('Content-Type', 'text/html');
var pl_list = ["test", "test2"];
Promise
.all(pl_list.map(executePythonScript))
.then(function (scripts) {
scripts.forEach(function (script) {
res.write(JSON.stringify({
finsihed: true,
product_line: script
}));
});
res.end();
})
.catch(function (err) {
res.end();
});
});
app.listen(5000, function () {
console.log('The web server is running. Please open http://localhost:5000/ in your browser.');
});
I am using the "ws" NodeJS websocket library. Previously I was trying out socket.io; with socket.io I could implement callbacks between the client and server like this:
socket.emit('Data', data, function(data){
console.log(data);
});
socket.on('Data', function(data, callback){
callback('it worked');
});
I have tried to do the same thing using the ws library, but have not had any success. Is it possible, and if so how?
The API is pretty similar and you can do pretty much the same things.
For example on the server side instead of:
s.emit('message', 'message from server');
you use:
s.send('message from server', ()=>{});
To receive it on the client side instead of:
s.on('message', function (m) {
// ...
});
you use:
s.addEventListener('message', function (m) {
// ...
});
And so on.
In this answer I showed example code (both frontend and backend) to demonstrate the difference between Socket.io and WebSocket:
Differences between socket.io and websockets
This is example server code:
var path = require('path');
var app = require('express')();
var ws = require('express-ws')(app);
app.get('/', (req, res) => {
console.error('express connection');
res.sendFile(path.join(__dirname, 'ws.html'));
});
app.ws('/', (s, req) => {
console.error('websocket connection');
for (var t = 0; t < 3; t++)
setTimeout(() => s.send('message from server', ()=>{}), 1000*t);
});
app.listen(3001, () => console.error('listening on http://localhost:3001/'));
console.error('websocket example');
Example browser code:
var l = document.getElementById('l');
var log = function (m) {
var i = document.createElement('li');
i.innerText = new Date().toISOString()+' '+m;
l.appendChild(i);
}
log('opening websocket connection');
var s = new WebSocket('ws://'+window.location.host+'/');
s.addEventListener('error', function (m) { log("error"); });
s.addEventListener('open', function (m) { log("websocket connection open"); });
s.addEventListener('message', function (m) { log(m.data); });
See this for more info.
This can be done with WebSockets-Callback like this
wscb.send({cmd: 'Hello server!'},
function(response){
//do something...
}
)
I've set up a NodeJS server which can be accessed by a client. Every once in a while it's necessary to let the server connect to a second server and feed the information retrieved back to the client.
Connecting to the second server is the easy part, but to be honest I have no idea how to send it back to the client. res.write seems to be forbidden during the connection with the second server.
The connection from the client is handled by handleGetRequest. The connection with the second server starts at http.get.
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var url_parsed = url.parse(req.url, true);
if (req.method ==='GET') {
handleGetRequest(res, url_parsed);
} else {
res.end('Method not supported');
}
});
handleGetRequest = function(res, url_parsed) {
if (url_parsed.path == '/secondary') {
var OPTIONS = {
hostname: "localhost",
port: "8900",
path: "/from_primary"
}
http.get(OPTIONS, function(secget) {
resget.on('data', function(chunk) {
// either store 'chunk' for later use or send directly
});
}).on('error', function(e) {
console.log("Error " + e.message);
});
} else {
res.writeHead(404);
}
res.end('Closed');
};
server.listen(8000);
How do I send the chunk from http.request to the client?
I thinks passing the callback to the handleGetRequest will fix this issue:
if (req.method === 'GET') {
handleGetRequest(url_parsed, function (err, response) {
if (err) {
return res.sendStatus(500);
}
res.json(response);
});
} else {
res.end('Method not supported');
}
handleGetRequest = function (url_parsed, callback) {
// OPTIONS ...
http.get(OPTIONS, function(resget) {
var data = '';
resget.on('data', function(chunk) {
data += chunk;
});
resget.on('end', function() {
callback(null, data);
});
}).on('error', function(e) {
callback(e);
});
}
Thanks to #TalgatMedetbekov for the suggestions. I managed to implement it like this:
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var url_parsed = url.parse(req.url, true);
if (req.method ==='GET') {
handleGetRequest(res, url_parsed);
} else {
res.end('Method not supported');
}
});
handleGetSecondaryRequest = function(callback, res) {
var OPTIONS = {
hostname: "localhost",
port: "8900",
path: "/from_primary"
}
var data = null;
http.get(OPTIONS, function(func, data) {
func.on('data', function(chunk) {
data += chunk;
});
func.on('end', function() {
callback(res, data);
});
}).on('error', function(e) {
callback(res, e);
})
};
var secReqCallback = function(res, recData)
{
res.write(recData);
res.end("END");
};
handleGetRequest = function(res, url_parsed) {
if (url_parsed.path == '/secondary') {
handleGetSecondaryRequest(secReqCallback, res);
} else {
res.writeHead(404);
}
};
server.listen(8000);
It works, kind of. There's an 'undefined' in front of the string which I can't find the cause for, but the basic functionality works perfect.
The callback construction is necessary to synchronize the asynchronous nature of NodeJS.
i made an app with socket.io.my problem is when i close node and open again server response count is up.first time 1 resutlset sending but second time 2 and third time 3 and so on? what is the problem
client code is
<script>
var socket = io.connect('http://10.0.0.192:8888');
socket.on('connecting', function () {
console.log('connecting');
});
socket.on('connect', function(s){
console.log('connect');
socket.emit('Baglan');
console.log('emit-Baglan');
socket.on('guncelle',function(data){
console.log(new Date().getMilliseconds());
console.dir(data);
});
});
socket.on('reconnecting', function () {
console.log('reconnecting');
});
socket.on('reconnect', function () {
console.log('reconnect');
});
socket.on('reconnect_failed', function () {
console.log('reconnect_failed');
});
</script>
and server
function getDataForClients() {
var d = new Array();
d.push({records:res});
//console.log(d);
return d;}
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
//console.log("Request for " + pathname + " received.");
route(handle, pathname, response, request);
}
server = http.createServer(onRequest);
io = require('socket.io').listen(server);
io.set('log level', 1);
io.sockets.on('connection', function (client) {
//console.log(client);
client.on("Baglan",function(){
//console.log("user connected");
__sockets.push(client);
client.room="weather";
client.records=[];
client.join(client.room);
if(!res)
guncelle(false,client);
else
client.emit("guncelle",getDataForClients());
});
client.on('disconnect', function(){
var i = __sockets.indexOf(client);
__sockets.splice(i,1);
client.leave(client.room);
//console.log("user leave");
});
});
server.listen(8888);
function guncelle(v,c) {
//console.log("update");
var db = mysql.createClient({
user: 'user',
password: '***',
});
db.query('USE '+TEST_DATABASE);
db.query(
"select * from table",
function selectCb(err, results, fields) {
if (err) {
throw err;
}
res = results;
var _data = getDataForClients();
if(v)
io.sockets.emit("guncelle",_data);
else
c.emit("guncelle",_data);
db.end();
}
);
}
there are 5 result between 15 ms.
sorry i cant post image.