Connect web and mobile api with socket using node.js - node.js

I'm new in node and socket programming.
In my project Requirement is like this,
One Server which house the set of questions and set of campaigns. campaigns contains questions. And admin will start or stop campaign.
Once Campaign start, Front end of Web Application will display only questions and mobile application display Answer of question and question will automatic reload after every X second in both web and mobile app.
I tried web socket and socket.io this is working fine for web application requirement. But I don't know what for mobile API.
Below is the code for socket.io.
server.js
var mysql = require('mysql');
// Let’s make node/socketio listen on port 3000
var io = require('socket.io').listen(3000);
// Define our db credentials
var db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '****',
database: 'database_name'
});
// Log any errors connected to the db
db.connect(function (err) {
if (err)
console.log(err);
});
// Define/initialize our global vars
var questions = [];
var total_question = 0;
var isInitNotes = false;
var count = 0;
var sql = "";
// call once per connection, create new connection
io.sockets.on('connection', function (socket) {
console.log((new Date()) + ' Connection from origin ' + socket.handshake.headers.origin);
//io.sockets.emit('users connected', socketCount)
socket.on('disconnect', function () {
console.log((new Date()) + ' Disconnected from origin ' + socket.handshake.headers.origin);
});
db.query('SELECT COUNT(vQuestion) as total_question FROM questions')
.on('result', function (data) {
// Push results onto the questions array
total_question = data.total_question;
});
// select questions from DB
var questionInterval = setInterval(function () {
// check condition for question is over or not
if (count < total_question) {
sql = 'SELECT vQuestion FROM questions LIMIT ' + count + ',1';
console.log(sql);
db.query(sql)
.on('result', function (data) {
// Push results onto the questions array
questions.pop();
questions.push(data);
})
.on('end', function () {
// Only emit questions after query has been completed
socket.emit('get questions', questions);
});
count++;
} else {
clearInterval(questionInterval);
}
}, 5000);
isInitNotes = true;
});
Index.html
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://localhost:3000/socket.io/socket.io.js"></script>
<script>
$(document).ready(function(){
// Connect to our node/websockets server
var socket = io.connect('http://localhost:3000');
// Initial set of questions, loop through and add to list
socket.on('get questions', function(data){
var html = ''
for (var i = 0; i < data.length; i++){
// We store html as a var then add to DOM after for efficiency
html += '<li>' + data[i].vQuestion + '</li>'
}
$('#questions').append(html)
})
})
</script>
<ul id="questions"></ul>
<div id="usersConnected"></div>
Commands for server
node server.js
Fri Oct 21 2016 10:30:35 GMT+0530 (IST) Connection from origin http://localhost
Web browser (Web Application)
http://localhost//index.html
display a question every 5 seconds.
In my case, Only one web Application will be there but, More than one mobile users will connect at same time.

Related

Simple Chat application with NodeJS [duplicate]

This question already has answers here:
socket.emit in a simple TCP Server written in NodeJS?
(3 answers)
Closed 5 years ago.
I am new to NodeJS and started to learn by building a simple command line chat application. I have the following code for Server and Client. Client-Server communication is successful but I am not able to capture 'adduser' event from the client. Please tell me where I am going wrong.
Server:
var net = require('net');
var chatServer = net.createServer(function(socket){
socket.pipe(socket);
}),
userName="";
chatServer.on('connection',function(client){
console.log("ChatterBox Server\n");
client.write("Welcome to ChatterBox!\n");
client.on('data',function(data){
console.log(""+data);
});
client.on('adduser',function(n){
console.log("UserName: "+ n);
userName = n;
});
});
chatServer.listen(2708);
Client:
var net = require('net');
var client = new net.Socket();
client.connect(2708,'127.0.0.1');
client.on('connect',function(){
client.emit('adduser',"UserName");
});
console.log("Client Connected!\n");
client.on('data',function(data){
console.log(""+data);
});
I guess you don't have to do from the client side :
client.connect(2708,'127.0.0.1');
Just write your client like this is sufficient.
var net = require('net');
var client = new net.Socket();
client.connect(2708, '127.0.0.1',function(){
console.log("Client Connected!\n");
client.emit('adduser',"UserName");
});
client.on('data',function(data){
console.log(""+data);
});
client.on('close', function() {
console.log('Connection closed');
});
So the server side :
var net = require('net');
var sockets = [];
var port = 2708;
var guestId = 0;
var server = net.createServer(function(socket) {
// Increment
guestId++;
socket.nickname = "Guest" + guestId;
var userName = socket.nickname;
sockets.push(socket);
// Log it to the server output
console.log(userName + ' joined this chat.');
// Welcome user to the socket
socket.write("Welcome to telnet chat!\n");
// Broadcast to others excluding this socket
broadcast(userName, userName + ' joined this chat.\n');
socket.on('adduser',function(n){
console.log("UserName: "+ n);
userName = n;
});
// When client sends data
socket.on('data', function(data) {
var message = clientName + '> ' + data.toString();
broadcast(clientName, message);
// Log it to the server output
process.stdout.write(message);
});
// When client leaves
socket.on('end', function() {
var message = clientName + ' left this chat\n';
// Log it to the server output
process.stdout.write(message);
// Remove client from socket array
removeSocket(socket);
// Notify all clients
broadcast(clientName, message);
});
// When socket gets errors
socket.on('error', function(error) {
console.log('Socket got problems: ', error.message);
});
});
// Broadcast to others, excluding the sender
function broadcast(from, message) {
// If there are no sockets, then don't broadcast any messages
if (sockets.length === 0) {
process.stdout.write('Everyone left the chat');
return;
}
// If there are clients remaining then broadcast message
sockets.forEach(function(socket, index, array){
// Dont send any messages to the sender
if(socket.nickname === from) return;
socket.write(message);
});
};
// Remove disconnected client from sockets array
function removeSocket(socket) {
sockets.splice(sockets.indexOf(socket), 1);
};
// Listening for any problems with the server
server.on('error', function(error) {
console.log("So we got problems!", error.message);
});
// Listen for a port to telnet to
// then in the terminal just run 'telnet localhost [port]'
server.listen(port, function() {
console.log("Server listening at http://localhost:" + port);
});
So you've got an object "users" inside the "user" when is connected, push user to the array users but you need to do (server side) on('close', ... to remove the user from users when connected is false ... etc

socket.broadcast.to(receiver_socket_id) emitting n number of data (instead of one) to the receiver, where n is the number of user connected

I am using socket.io for private chatting for the server side I am using
socket.broadcast.to(receiver_socket_id).emit('message', data); // where data is a json object containing text
And at the client side code I catch the data using
socket.on('message', function (data) {
alert(data. text);
});
Its working properly and showing the alert on that specific user (socket id) ‘s panel when only two socket are connected (sender and receiver). But the problem appears when one more user connects to that socket then I see two alerts and when total 4 user connected (sender + receiver + two others) then see 3 alerts. But the good point is I can see the alerts only that specific client's panel not the others.
I can’t understand the problem, please help.
Please have a look on it
gyazo.com/a98d3a64a9fc6487e6ded8ccd90fd5ab
it prints test three times because three browsers are opened.
Full code here:
Sever side (I have used Redis):
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
server.listen(8080);
var usernames = {};
io.on('connection', function (socket) {
console.log(socket.id);
socket.on('adduser', function (userId) {
usernames[userId] = socket.id;
});
var redisClient = redis.createClient();
redisClient.subscribe('message-channel');
redisClient.on('message', function (channel, data) {
var jsonObj = JSON.parse(data);
var rcvrId = jsonObj.rcvrId;
socket.broadcast.to(usernames[rcvrId]).emit('message', data); // Not throwing error....should work
});
socket.on('disconnect', function () {
console.log(socket.id + ' Disconnected');
redisClient.quit();
});
});
Client side:
var socket = io.connect('http://localhost:8080');
var userId = $('input[name="userId"]').val();
var rcvrId = $('input[name="rcvrId"]').val();
socket.on('connect', function () {
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser', userId);
});
socket.on('message', function (data) {
data = jQuery.parseJSON(data);
console.log(data);
$("#messages").append("<div><strong>" + data.userId + " : </strong><span>" + data.message + "</span></div>");
});
You can use io.of('/').sockets[rcvrId].emit('message', data). In case you are using a different namespace just replace the / with your namespace.

Memory leak when running Nodejs socket.io on AWS EC2 t2.micro

I want to check the max connections for websocket that t1.micro instance (1GB RAM) can be handle.
So I simple example to check it with nodejs(v6.2.1) and socket.io#1.4.6.
Here is the code on server:
require("http").globalAgent.maxSockets = Infinity;
var http = require('http').createServer(function(req, res) {});
var io = require('socket.io')(http);
io.on('connection', function(socket){
socket.on('echo me', function (data) { //receive msg from client
var msg = {msg: data.msg};
io.emit('echo me', msg);
delete msg.msg;
});
});
var clock = setInterval(function(){
global.gc();
}, 2000);
http.listen(3000, function(){
console.log('listening on *:3000');
});
And code on client
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script type="text/javascript">
var n = 20;
var socket = [], id = [];
for(var i = 0; i < n; ++i){
socket[i] = io('http://aws_ip_address');
socket[i].on('connect', function(){
id.push(this.io.engine.id);
console.log('Connected to Server. My name is ');
});
socket[i].on('echo me', function(data){ //receive message from server
console.log(data.msg);
});
}
var inv = setInterval(function(){
sendEchoToServer();
}, 1000); //1 second
function sendEchoToServer(){
for(var i = 0; i < n; ++i){
var msg = 'My name is ' + id[i] + ' with msg: ' + Math.random();
socket[i].emit('echo me', {msg: msg});
}
}
</script>
The problem I got. When I open 10 tabs (200 connections) on clients, the memory increase minutes by minutes. And if I open 350 connections, the server can't handle in 5 minutes (The OS kill it). The CPU getting 100%.
I want it can handle more than 500 connections, is it possible?
Thanks in advanced.
You can change the memory handling in node to be more agressive.
More on the options available:
https://gist.github.com/listochkin/10973974​
node --expose-gc --optimize_for_size --max_old_space_size=460 --gc_interval=100 app.js

nodejs + mysql + individual user

I am trying to build a client which will send the id ( ex. email ) to nodejs program on server. Email will actually be of the logged-in user.
And nodejs program should keep updating a particular div on client side(say pushing data every 3 seconds) with relevant data for that email address.
Same should be done on multiple machines, wherein every machine has separate person logged-in via email. Something like what happens on gmail.
I have built it as follows, but when i open it from multiple clients, the value of latest client(email) overwrites the value of previous ones and all client show data for latest email only.
Code is as shown below for both server and client.
server.js
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
profile_id,
last_count = 0, //this variable is to check previous count value
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '', //put your own mysql pwd
database: 'test', //put your database name
port: 3306
}),
POLLING_INTERVAL = 1000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
console.log('DB connected');
// creating the server ( localhost:8000 )
app.listen(8000);
// on server started we can load our client.html page
function handler(req, res) {
fs.readFile(__dirname + '/indexnew.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
console.log('File loaded');
res.writeHead(200);
res.end(data);
});
}
/*
* HERE IT IS THE COOL PART
* This function loops on itself since there are sockets connected
* to the page. Upon Update it only emits the notification if
* the value has changed.
* Polling the database after a constant interval
*/
var pollingLoop = function() {
sql = "SELECT count(*) as c FROM activity_log WHERE notified=0 and (profile_id = '" + profile_id + "')";
console.log(sql);
// Doing the database query
var query = connection.query(sql),
users = []; // this array will contain the result of our db query
// setting the query listeners
query
.on('error', function(err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function(count) {
// it fills our array looping on each user row inside the db
users.push(count);
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
users: users,
count: count.c
});
}
})
};
// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function(socket) {
console.log('Connected');
//This variable is passed via the client at the time of socket //connection, see "io.connect(..." line in client.html
profile_id = socket.handshake.query.profile_id;
console.log('Number of connections:' + connectionsArray.length);
// starting the loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function() {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socket = ' + socketIndex + ' disconnected');
if (socketIndex >= 0) {
connectionsArray.splice(socketIndex, 1);
}
});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function(data) {
if (last_count != data.count) {
// adding the time of the last update
data.time = new Date();
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
}
last_count = data.count;
};
indexnew.html
<html>
<head>
<title>Push notification long polling server streaming on a MySQL db</title>
<style>
dd,
dt {
float: left;
margin: 0;
padding: 5px;
clear: both;
display: block;
width: 100%;
}
dt {
background: #ddd;
}
time {
color: gray;
}
</style>
</head>
<body>
<time></time>
<div id="container">Loading ...</div>
<script src="socket.io.js"></script>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
var rno = Math.floor((Math.random() * 10) + 1);
// create a new websocket
var socket = io.connect('http://localhost:8000/?profile_id=' + rno);
// on message received we print all the data inside the #container div
socket.on('notification', function(data) {
var usersList = "<dl>";
$.each(data.users, function(index, count) {
usersList += "<dt>" + count.c + "</dt>\n";
});
usersList += "</dl>";
$('#container').html(usersList);
$('time').html('Last Update:' + data.time);
$('sql').html('Last Update:' + data.sql);
});
</script>
</body>
</html>
The way your pollingLoop function and query is structured you will only ever retrieve the last profile_id. Here is why:
The profile_id variable is a global variable, existing on the server thread. The way you've programmed it so far, it seems that you want your pollingLoop to handle all of your sockets at once, but then inside the pollingLoop, you use the global variable profile_id to pull down the information from the database. Every time a new user connects the 'connected' event fires, which updates the profile_id to that user.
Here are some options for what you can do to solve for this:
Construct your query to pull all the profile_id's that are connected,
and build your update_sockets to only send the count for each
profile_id to the appropriate socket.
You can use "group by" to help
with your counts. You could make the pollingLoop run for each
connected user individually. You could keep your query as it is.
Either way you will have to fix your profile_id, because it doesn't make sense to have it contain a single user's unique id in a global setting. If you truly want the profile_id to be a session-based unique ID, doing a random number is a bit dangerous. I would suggest using the socket.id that socket.io exposes for each socket. This way you don't have to worry about it being unique, you don't have to pass it along, and you don't have to store it yourself. The socket.id will be available to you in the connectionsArray since that contains all your sockets. So in the pollingLoop you can loop over the ID's to construct your query, and in the updateSockets you can pair the results back to the socket that needs to receive the data particular to that user.
One more note about a comment in your connection event:
// starting the loop only if at least there is one user connected
This comment is inaccurate, I think it should say:
// starting the loop only if there are no other users connected yet
I hope that helps you!

Socket 1.0 repeating connect multiple times

I'm using Heroku + RedisToGo + Express 4.0 + socket.io 1.0.6.
I just recently upgraded to 1.0 from 0.9, and it's half working now. I've hacked together a app from tutorials but my lack of understanding socket.io is showing, so I'm taking a step back. The first question I have is that now socket.on('connect') is happening repeatedly, without stop, even when a connection is successful. My client-side console.log just keeps going and going. Here's client-side:
// Connect the user
socket.on('connect', function(){
var currentUserId = '<%= currentUser.id %>';
// Add user to redis
socket.emit('login', { userID: currentUserId});
// Retrieve presence info
socket.emit('presence');
});
// Show Presence
socket.on('presence', function(data) {
var userID = data.user;
var presence = data.presence;
if (presence) {
$('#red-dot-' + userID).css("display", "none");
$('#green-dot-' + userID).css("display", "inline");
// Show the hangout button
$('#hangout-' + userID).show();
$('#hangout-unavail-' + userID).hide();
}
else {
$('#red-dot-' + userID).css("display", "inline");
$('#green-dot-' + userID).css("display", "none");
}
});
And server-side:
io.sockets.on('connection', function (socket) {
var savedUserID;
socket.on('login', function(data){
var userID = data.userID;
savedUserID = userID;
// add first user
redis.sadd("users", userID);
redis.hmset("users:"+userID, "socketID", socket.id, "userID", userID);
});
socket.on('presence', function(){
// Get the list of online users and show Presence
redis.smembers("users", function(err,results) {
var onlineUsers = results;
for (var i in onlineUsers) {
var userID = redis.hget("users:"+onlineUsers[i],"userID", function(err,reply) {
var userID = reply;
// Emit presence
io.sockets.emit('presence', {
user: userID,
presence: "true"
});
});
}
});
});
As you can see I'm manually adding users to redis.
I found the answer in this Google Group thread.
The problem occurred because I had socket.emit('presence'); in my socket.on('connect', function(){}); client-side.
This in turn called socket.on('presence', function(){}); server-side, which was the problem.

Resources