Socket.io dilemma with clients.length (where clients === io.sockets.clients();) - javascript

Normally, when I send some JSON from one client to another, it works fine. But if there is only one client, it still sends packets. My solution was to (on the server-side, in node.js):
var clients = io.sockets.clients();
if(clients.length > 1){
// send stuff to other client
}
But when I do that, something extraordinarily strange occurs. I'll open up a client, start instigating the actions during the if statement, and the console, which prints the JSON before sending it, does nothing, because there is only one client. When I open up another client and instigate the actions during the if statement, the console will print out the JSON and send it to my other client. However, if I go over to my first client that I opened and instigate the actions in the if statement, the console won't print anything out, and it won't send anything. Why? I tried changing the if statement to say:
if("hello" === "hello"){
// do the same stuff as before
}
and both clients could send JSON to one another, but because I had changed the if statement, with one client open I would still send useless packets. For obvious reasons, the optimal situation would be if it wouldn't send packets with one client, but would send packets properly with more than one.
I hope that was clear, I'm sorry if that wasn't.
If I need to, I'll post more code.
EDIT:
Here is the code that updates the array:
var clients = io.sockets.clients();
io.sockets.on("connection", function (socket) {
clients.length++;
socket.on("disconnect", function() {
clients.length--;
console.log(clients.length + " clients are connected");
});
console.log(clients.length + " clients are connected");
});

Haven't done any note.js lately, maybe this is bogus. But I thought: maybe the clients variable is defined for each client when he connects, and not updated later on. This seems the logic thing to me. I think that what you need to do is: fire an event to all clients when a new client connects, and update the "clients" variable.

I'm not sure how your code works (what's this: clients.length++ ?? Incrementation of array's length??) but try doing this the "normal" way:
var clients;
io.sockets.on("connection", function (socket) {
clients = io.sockets.clients();
socket.on("disconnect", function() {
clients = io.sockets.clients();
console.log(clients.length + " clients are connected");
});
console.log(clients.length + " clients are connected");
});
or even better (without holding global reference to connected users):
function get_clients() {
var clients = io.sockets.clients();
console.log(clients.length + " clients are connected");
}
io.sockets.on("connection", function (socket) {
socket.on("disconnect", function() {
get_clients();
});
get_clients();
});
Because io.sockets.clients() returns the array of all connected clients at the moment of calling it (perhaps that's why you get this strange behaviour).

Related

Send data to certain client using client ID with websocket and node.js

I am creating customer service chat application that get data from client website to node.js server then send this data to agent and the agent reply to the client..
Server code:
var ws = require("nodejs-websocket");
var clients = [];
var server = ws.createServer(function(conn){
console.log("New Connection");
//on text function
conn.on("text", function(str){
var object = JSON.parse(str);
conn.sendText("Message send : " + object);
console.log("User ID: " + object.id);
clients.push(object.id);
var unique=clients.filter(function(itm,i,a){
return i==a.indexOf(itm);
});
/*
conn.on('message', function("test") {
console.log('message sent to userOne:', message);
unique[0].send("Message: " + message);
});
*/
console.log("Number of connected users : " + unique.length);
//closing the connection
conn.on("close", function(){
console.log("connection closed");
});
});
}).listen(process.env.PORT, process.env.IP);
Everything works perfectly and I have each client ID but the
I want to reply with a message to that client ID..
What I have tried:
I have tried to reply to the client using conn.send("message", callBackFunction) but it send to all not with a specified user ID.
Disclaimer: co-founder of Ably - simply better realtime
You have two problems there I suspect. Firstly, if you ever need to scale to more than one server you've got problems as you will need to figure out how to pass messages between servers. Secondly, you have no way of maintaining state between disconnections which will happen as part of normal behaviour for clients.
The industry typically approaches this type of problem using the concept of channels as it scales, it decouples the publisher from the subscriber, and it's quite a simple concept to work with. For example, if you had a channel called "client:1" and you published to that channel, and your subscriber was listening on that channel, then they would receive the message. You can find out more about how we have designed our realtime service around channels, I would suggest you do consider that pattern in your system.
Matt, co-founder, Ably

node.js - should socket.get work on client?

I'm new to node.js and I'm making a simple chat app to get started. I'm a bit confused with the socket.set and socket.get methods.
The way the app works, is - first the client sets its username (pseudo):
function setPseudo() {
if ($("#pseudoInput").val() != "")
{
socket.emit('setPseudo', $("#pseudoInput").val());
$('#chatControls').show();
$('#pseudoInput').hide();
$('#pseudoSet').hide();
}
}
On the server, the pseudo is fetched with:
socket.on('setPseudo', function (data) {
socket.set('pseudo', data);
});
If I understand correctly, the server sets the pseudo variable with data received from this particular client. The server can later get that variable with socket.get. The following code broadcasts a message from a client to all clients:
socket.on('message', function (message) {
socket.get('pseudo', function (error, name) {
var data = { 'message' : message, pseudo : name };
socket.broadcast.emit('message', data);
console.log("user " + name + " send this : " + message);
})
});
What I don't understand is, why can't the client itself use socket.get to fetch its own pseudo? Using socket.get('pseudo') gives an error saying socket.get is not a function. Or am I overcomplicating this, and it would be better to just store the pseudo in a hidden field on the client or something similar? It just feels strange that a client should have to get its own username from the server.
EDIT:
Upon clicking Send, this code displays the sent message on the client itself. However, the displayed username is "Me". How can I modify it to show the client's username from the server?
addMessage($('#messageInput').val(), "Me", new Date().toISOString(), true);
function addMessage(msg, pseudo) {
$("#chatEntries").append('<div class="message"><p>' + pseudo + ' : ' + msg + '</p></div>');
}
You have to realize that although socket is a name used by both the server and the client, and interfaces are similar these are two independent things. (i.e. server socket and client socket) describing two ends of one connection.
If server sets some data on a socket what it actually does is it saves some data in its own memory and remembers that this data is associated with the socket. So how would client read something from server's memory? How can machine A read data from machine's B memory? Well, the only (reasonable) possibility is to send that data over network and this is actually what happens.
As for the other question: it's actually natural for the client to get its own name from the server or at least validate that name. Consider this scenario: two clients connect to the server and use the same name. This would lead to a conflict so it is up to the server to solve the problem. Basically you would tell one of the clients "sorry, this name is already being used, use something else".

nodejs socket emit return undefined

I am trying to send to clients whenever a new connection issued.
My server side javascripts is :
var clients = 0;
io.sockets.on('connection', function (socket) {
clients ++;
console.log(clients);
socket.broadcast.emit('connect',socket.clients);
}
and my client side js to handle:
socket.on('connect', function (data) {
console.log('on'+data);});
the output is undefined (on undefined)
Where 's things wrong?
socket.broadcast.emit('connect',socket.clients);
^^^^^^^^^^^^^^ this should be 'clients'
Also, connect is a pre-defined event with socket.io, so you shouldn't reuse it or it might give unexpected results.
FWIW: socket.broadcast.emit will send a message to all connections except the current one. If that's not what you want (you want the message to be sent to all connections), use io.sockets.emit instead).

socket.io not working on several clients

I'm trying to build a simple chat client and am having some issues getting it working across multiple clients. Chances are I've missed something really simple. When I send something from one client it is logged in that client but not in any others.
Server:
var io = require('socket.io').listen(5000);
io.sockets.on('connection', function (socket) {
socket.on('send', function (data) {
socket.emit('receive', data);
});
});
Client:
var socket = io.connect('http://localhost:5000');
socket.on('receive', function(data){
console.log("Data received at " + new Date() + ": " + data);
});
The socket variable that gets passed to your callback function is a handle on the client that connected, so socket.emit is behaving correctly, i.e. it should only send to the client that originated it.
Try:
socket.broadcast.emit('receive', data);
to send to everybody except the originating client, or
io.sockets.emit('receive', data);
to send to all clients including the originator.
You want to emit on all sockets, not just the one that sent the message.
So you should be using:
io.sockets.emit('recieve', data);
This is assuming that you aren't logging the data on the sending client before sending it to the server. In that case you'll want to use:
socket.broadcast.emit('recieve', data);
Which will send the message to all connected clients except the sender.
See here for reference on Socket.io
Edit: Trevor beat me to it. However, for some additional clarification: io.sockets is the same as io.of(''). Which is handy to know for when you start using namespaces in a scoket.io app.

Socket IO Server to Server

Is it possible for a server to connect to another using Socket.IO and be treated like a client?
And have it join rooms, recieve io.sockets.in('lobby').emit(). And more?
The first server is also listening for connections/messages as well.
Hey Brad, here's my full .js app below for reference:
var io = require("socket.io").listen(8099);
io.set('log level', 1);
io.sockets.on("connection", function (socket) {
console.log('A Client has Connected to this Server');
//Let Everyone Know I just Joined
socket.broadcast.to('lobby').emit("message",'UC,' + socket.id); // Send to everyone in Room but NOT me
socket.on("message", function (data) {
//Missing code
socket2.send('message,' + data); //Forward Message to Second Server
});
socket.on("disconnect", function (data) {
//Send Notification to Second Server
//Need to figure out later
//Send Notification to Everyone
socket.broadcast.emit("message",'UD,' + socket.id ); //Send to Everyone but NOT me
//Remove user from Session ID
arSessionIDs.removeByValue(socket.id);
//Send Notification to Console
console.log("disconnecting " + arRoster[socket.id][1]);
});
});
var io_client = require( 'socket.io-client' );
var socket2 = io_client.connect('http://192.168.0.104:8090');
socket2.on('connect', function () {
socket2.emit('C3434M,Test');
});
Yes, absolutely. Just use the Socket.IO client in your server application directly.
https://github.com/LearnBoost/socket.io-client
You can install it with npm install socket.io-client. Then to use:
var socket = io.connect('http://example.com');
socket.on('connect', function () {
// socket connected
socket.emit('server custom event', { my: 'data' });
});
I realize this is an old post, but I was working on something similar and decided to come back and contribute something as it got me thinking.
Here's a basic Client -> Server 1 -> Server 2 setup
Server #1
// Server 1
var io = require("socket.io").listen(8099); // This is the Server for SERVER 1
var other_server = require("socket.io-client")('http://example.com:8100'); // This is a client connecting to the SERVER 2
other_server.on("connect",function(){
other_server.on('message',function(data){
// We received a message from Server 2
// We are going to forward/broadcast that message to the "Lobby" room
io.to('lobby').emit('message',data);
});
});
io.sockets.on("connection",function(socket){
// Display a connected message
console.log("User-Client Connected!");
// Lets force this connection into the lobby room.
socket.join('lobby');
// Some roster/user management logic to track them
// This would be upto you to add :)
// When we receive a message...
socket.on("message",function(data){
// We need to just forward this message to our other guy
// We are literally just forwarding the whole data packet
other_server.emit("message",data);
});
socket.on("disconnect",function(data){
// We need to notify Server 2 that the client has disconnected
other_server.emit("message","UD,"+socket.id);
// Other logic you may or may not want
// Your other disconnect code here
});
});
And here's Server #2
// Server 2
var io = require("socket.io").listen(8100);
io.sockets.on("connection",function(socket){
// Display a connected message
console.log("Server-Client Connected!");
// When we receive a message...
socket.on("message",function(data){
// We got a message. I don't know, what we should do with this
});
});
This is our Client, who sends the original message.
// Client
var socket = io('http://localhost');
socket.on('connect', function(){
socket.emit("message","This is my message");
socket.on('message',function(data){
console.log("We got a message: ",data);
});
});
I am making this post a Community Wiki so that someone can improve this if they feel like it.
The code has not been tested, use at your own risk.
I had the same problem, but instead to use socket.io-client I decided to use a more simple approach (at least for me) using redis pub/sub, the result is pretty simple.
You can take a look at my solution here: https://github.com/alissonperez/scalable-socket-io-server
With this solution you can have how much process/servers you want (using auto-scaling solution), you just use redis as a way to forward your messages between your servers.

Categories

Resources