How can I send packets between the browser and server with socket.io, but only when there is more than one client? - node.js

In my normal setup, the client will emit data to my server regardless of whether or not there is another client to receive it. How can I make it so that it only sends packets when the user-count is > 1? I'm using node with socket.io.

To do this you would want to listen to the connection event on your server (as well as disconnect) and maintain a list of clients which are connected in a 'global' variable. When more than 1 client is connected send out a message to all connected clients to know they can start sending messages, like so:
var app = require('express').createServer(),
io = require('socket.io').listen(app);
app.listen(80);
//setup express
var clients = [];
io.sockets.on('connection', function (socket) {
clients.push(socket);
if (clients.length > 1) {
io.socket.emit('start talking');
}
socket.on('disconnect', function () {
var index = clients.indexOf(socket);
clients = clients.slice(0, index).concat(clients.slice(index + 1));
if (clients.length <= 1) {
io.sockets.emit('quiet time');
};
});
});
Note: I'm making an assumption here that the socket is passed to the disconnect event, I'm pretty sure it is but haven't had a chance to test.
The disconnect event wont receive the socket passed into it but because the event handler is registered within the closure scope of the initial connection you will have access to it.

Related

Socket IO doesn't get emitted from client - Node JS

I am working on Socket IO, the connection between the client and the server is established successfully. I am facing two problems:
1 - When the initial connection is made between the client and the server, the socket.client.id on server and socket.id on client side, both are the same, but when I refresh the client page, the id of the client changes to other one, but on the server it is still the same. Does it makes any issue / problem while communicating with the server or even with the client using sockets, while not having the same ids ? or does the id on the server get changed when the client page is refreshed ?
2 - On the initial connection establishment the socket passes a messages, using socket.emit() from server and receives as socket.on() on client. But when I try to emit anything from client it doesn't get received on server.
Socket Connections
function Globals() {
this.socketConnection = async function() {
let p = new Promise(function(res, rej) {
io.on("connection", function(socket) {
if (socket.connected) {
res(socket);
} else {
rej("Socket Connection Error !");
}
})
})
return await p;
}
}
new Globals().socketConnection().then(function(soc) {
console.log(soc.client.id);
socket = soc;
soc.emit("Hi");
soc.on("Nady", function() {
console.log("I am called");
})
})
Client Side Connection
function Globals() {
this.socketConnection = async function() {
var socket = io('http://localhost:8080');
let p = new Promise(function(res, rej) {
socket.on('connect', function() {
if (socket.connected) {
console.log(socket.id);
res(socket);
}
})
})
return await p;
}
}
var socket;
new App().socketConnection().then(function(s) {
socket = s;
});
function ScrapJobs() {
var socket;
new App().socketConnection().then(function(s) {
socket = s;
});
var _this = this;
this.attachListeners = function() {
qs("#init-scrap").ev("click", _this.startScrapping);
}
this.startScrapping = function() {
console.log("I am cliced");
socket.on("Hi", function() {
console.log("Hi Nadeem");
})
socket.emit("Nady");
}
}
When the initial connection is made between the client and the server, the socket.client.id on server and socket.id on client side, both are the same, but when I refresh the client page, the id of the client changes to other one, but on the server it is still the same. Does it makes any issue
The client side socket.id value is set on the client socket object after the connect event is received and is updated (e.g. modified) upon a reconnect event.
It appears that the socket.io infrastructure will keep them the same on client and server. If the client disconnects and then reconnects, there will be a new connection with a new id on both client and server. It is possible you are attempting to hang onto the old socket object on the server after the client has disconnected it (we can't really see enough of your server code to evaluate that).
On the initial connection establishment the socket passes a messages, using socket.emit() from server and receives as socket.on() on client. But when I try to emit anything from client it doesn't get received on server.
You'd have to show us a reproducible case. This does not happen if you are coding things correctly. I would guess that you do not have the right listeners for messages on the right socket in order to see the messages you are sending. I promise you that sending a message from client to server works just fine when implemented properly.
A general comment about your code. Both code blocks you show appear to be stuffing a socket object into a higher scoped (or perhaps even global) variable. That is likely part the cause of your problem because that socket object can become dead if the client reconnects for any reason. Plus putting any sort of socket object into a global or module level variable makes your server only capable of serving one client - it's simply not how you design multi-client servers.

Combining Nodejs Net socket and Socket IO

I have a windows application (Built on C# as windows service) that sends data to NodeJs Net Socket, So since Socket.IO helps making a Web Application a live one , without the need of reload. How can i allow Socket.IO stream the received data from NodeJs Net Socket to the Web Application , in the exact moment the Net Socket receives data from C#?
So in the code that receives the socket data from C#:
var net = require('net');
net.createServer(function (socket) {
socket.on('data', function (data) {
broadcast(socket.name + "> \n" + data + " \n", socket);
socket.end("<EOF>");
//send data to web interface , does it work that way?
//SomeFooToSendDataToWebApp(Data)
});
});
Further more for the Socket.IO i have those lines , which i cant really figure out how to deal with them:
//Should it listen to net socket or web socket?
server.listen(8080);
// Loading socket.io
var io = require('socket.io').listen(server);
// It works but only for one request
io.sockets.on('connection', function (socket2) {
socket2.emit('message' , 'Message Text');
});
P.S: I am new to nodejs & socket.io , so if its possible as well to explain their behavior.
Edit 1 : My Front End Javascript to check it if it has any problems:
//for now it listens to http port , which Socket.IO listens to
var socket = io.connect('http://localhost:8080');
var myElement = document.getElementById("news");
socket.on('message', function(message) {
document.getElementById("news").innerHTML = message;
})
Edit 2 : Did follow jfriend00's answer as it seems my previous code tries were trying to send messages to an unknown socket, i only added this since i needed it to be sent to all the connected clients , so only one line fixed it !
socket.on('data', function (data) {
broadcast(socket.name + "> \n" + data + " \n", socket);
socket.end("<EOF>");
//send data to web interface , does it work that way?
//The Added code here:
io.emit('message',data + " more string");
});
It's a bit hard to tell exactly what you're asking.
If you have some data you want to send to all connected socket.io clients (no matter where the data came from), then you can do that with:
io.emit("someMessage", dataToSend);
If you want to send to only one specific connected client, then you have to somehow get the socket object for that specific client and then do:
socket.emit("someMessage", dataToSend);
How you get the specific socket object for the desired connected client depends entirely upon how your app works and how you know which client it is. Every socket connection on the server has a socket.id associated with it. In some cases, server code uses that id to keep track of a given client (such as putting the id in the session or saving it in some other server-side data). If you have the id for a socket, you can get to the socket with the .to() method such as:
io.to(someId).emit("someMessage", dataToSend);
Your question asked about how you send data received from some C# service over a normal TCP socket. As far as sending it to a socket client, it does not matter at all where the data came from or how you received it. Once you have the data in some Javascript variable, it's all the same from there whether it came from a file, from an http request, from an incoming TCP connection in your C# service, etc... It's just data you want to send.
You can try the following, simple server:
const io = require('socket.io')(8080);
io.on('connection', socket => {
console.log('client connected');
socket.on('data', data => {
io.emit('message', data);
});
});
console.log('server started at port 8080');
It should work if I understand the problem correctly.
And maybe document.getElementById("news").innerHTML += message; in the html client code to see what really happens there?
socket2 means your client which just connected. So you can store these connections to send data to them (helpful for broadcast).
If you get data from windows service via some polling mechanism, on this step you can send this message to your connected clients. So keep your connections in a array to send specific messages each client afterwards

How to send message to a specific client with socket.io if the application uses the cluster up and running in several processes on different ports?

The application starts in cluster mode, each worker is to establish a connection to the socket, using redis adapter:
app.set('port', httpPort);
let server = http.createServer(app);
let io = require('./socketServer')(server);
io.adapter(redis({host: host, port: port}));
app.set('io', io);
then we connect the main socket.io file (socketServer), where after authorization of the socket and on.connection event, we save sessionID in variable socketID, and store current socket connection in array io.clients
io.sockets.on('connection', (socket) =>{
var socketID = socket.handshake.user.sid;
io.clients[socketID] = socket;
io.clients[socketID].broadcast.emit('loggedIn',socket.handshake.user.data);
socket.on('disconnect', () =>{
delete io.clients[socketID];
});
});
Before nodejs app, we have nginx with customized "upstream" to organize a "sticky sessions" (http://socket.io/docs/using-multiple-nodes/#nginx-configuration).
Then, when we want to send a message to a particular customer, already from the controller we get id user, and get session-id for id (we pre-authorization keep these correspondences in redis), and then just send a message:
this.redis.getByMask(`sid_clients:*`,(err,rdbData) =>{
Async.each(clients,(client,next)=>{
let sid = `sid_clients:${client}`;
let currentClient = rdbData[sid];
if(!currentClient || !this.io.clients[currentClient]) return next();
this.io.clients[currentClient].emit(event,data);
return next();
});
It works fine when we run the application in a single process. But this don't work when running in a cluster mode. Connection message "loggedIn" is send to all customers on all processes. But if a single process to send a message to the client that connects to a server in another process - does not work, because that each process has own array io.clients and they are always have different content, so the message does not can reach the right customer.
So, how send events to the specific client in a cluster mode? How to keep all connected sockets in one place to avoid situations such as mine?

Reconnect socket in disconnect event

I am trying to reconnecct the socket after the disconnect event is fired with same socket.id here is my socket config
var http = require('http').Server(app);
var io = require('socket.io')(http);
var connect_clients = [] //here would be the list of socket.id of connected users
http.listen(3000, function () {
console.log('listening on *:3000');
});
So on disconnect event i want to reconnect the disconnected user with same socket.id if possible
socket.on('disconnect',function(){
var disconnect_id = socket.id; //i want reconnect the users here
});
By default, Socket.IO does not have a server-side logic for reconnecting. Which means each time a client wants to connect, a new socket object is created, thus it has a new id. It's up to you to implement reconnection.
In order to do so, you will need a way to store something for this user. If you have any kind of authentication (passport for example) - using socket.request you will have the initial HTTP request fired before the upgrade happened. So from there, you can have all kind of cookies and data already stored.
If you don't want to store anything in cookies, the easiest thing to do is send back to client specific information about himself, on connect. Then, when user tries to reconnect, send this information again. Something like:
var client2socket = {};
io.on('connect', function(socket) {
var uid = Math.random(); // some really unique id :)
client2socket[uid] = socket;
socket.on('authenticate', function(userID) {
delete client2socket[uid]; // remove the "new" socket
client2socket[userID] = socket; // replace "old" socket
});
});
Keep in mind this is just a sample and you need to implement something a little bit better :) Maybe send the information as a request param, or store it another way - whatever works for you.

node.js send userid client to server

Im having trouble to send the client costum userid to the node.js
For some reason it wont send the userid to the server to submit it. there is no output for it from the node log.
client sided:
var socket = io.connect('http://sitename.eu:1337/');
var user_id = <?echo $data->userid?>;
socket.on('connection',function(user_id) {
socket.emit('setuserid', user_id);
});
server sided:
io.on('connection', function (socket){ // just to prove that the code is inside it
logger.info('SocketIO > Connected socket ' + socket.id);
socket.on('setuserid', function (userId) {
users[userId]=socket;
socket.userid = userId;
logger.info("setting userid...");
});
only output:
2015-07-12T21:09:05.656Z - info: SocketIO > Connected socket E2ghiXGfTJWtgWs4AAAA
2015-07-12T21:09:08.134Z - info: SocketIO > Connected socket XY0c-A_ZveEUs_CuAAAB
2015-07-12T21:09:21.393Z - info: SocketIO > Disconnected socket E2ghiXGfTJWtgWs4AAAA
2015-07-12T21:09:22.610Z - info: SocketIO > Connected socket G3DmRKSymCuaximOAAAC
Change this line:
socket.on('connection',function(user_id) {
into:
socket.on('connect',function() {
Socket.io triggers an event called connect (http://socket.io/docs/client-api/#io#emitter). Since connection is never called, that function never gets run.
In addition, make sure you remove the user_id as a parameter.
Otherwise, you overwrite the global scope and will be sending undefined as a result for userid

Resources