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.
Related
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
I'm using socket.io-client to create a socket connection to my locally-running server. See my code below:
// Working example of connecting to a local server that is not SSL protected
var io = require('socket.io-client')
var socket = io.connect('http://localhost:3000', {reconnect: true});
socket.on('connect', function(){ console.log("inside 'connect'") } );
socket.on('connection', function(){ console.log("inside 'connection'") } );
socket.on('event', function(data){ console.log("inside 'event'") } );
socket.on('disconnect', function(){ console.log("inside 'disconnect'") } );
var payload = {email: 'fake#gmail.com', password: 'tester'};
var tokens = {browserId: 'b965e554-b4d2-5d53-fd69-b2ca5483537a'};
socket.emit("publish", {logic:"user", method:"signIn"}, payload, tokens, function(err, creds) {
console.log("inside the socket client emit callback. err: " + err);
console.log("creds: " + creds);
});
Now for my problem. As I stated in the comment at the top of that code, I can connect to my local nodejs server and get the response I expect when I turn off SSL encryption on my server. As soon as I turn SSL on, I stop getting any response at all from the code above. I don't see any message in my server logs or from the command line, where I'm running the code above with node.
My goal is to be able to run the code above, with SSL turned on in my server, and get the same response that I get when SSL is turned off. I've tried a bunch of variations on the code I included above, such as:
connecting to "https://localhost:3000"
connecting to "//localhost:3000"
connecting to "https://localhost:3443" (this is the port I have to connect to when I have the nodejs server running with SSL)
changing {reconnect:true} to {reconnect:true,secure:true}
I'm truly stumped, and I've been doing a bunch of research on the web and on my node server. It's my company's code and I didn't originally implement the SSL components, so I've spent a few hours looking at our code and trying to understand how adding SSL changes everything. I'm also a student and have about 2 years of experience behind me, so I'm good but I'm no expert. Have I said anything above that indicates if my task is impossible to achieve, or if maybe I have just overlooked something? Any leads on things to check out would be appreciated :)
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".
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.
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).