Having trouble managing multiple sockets [duplicate] - node.js

I'm having trouble getting basic client to client (or really client->server->client) working with socket.io. Heres the code I have right now:
io.sockets.on('connection', function (socket) {
users.push(socket.sessionId);
for(userID in users) {
console.log(userID);
io.sockets.socket(userID).emit('message', { msg: 'New User Connected succesfully' });
}
socket.emit('message', { msg: 'Connected succesfully' });
socket.on('my other event', function (data) {
console.log(data);
});
});
From my understanding, that should send the new user message to every connected user (individually, since i want to do actual individual messages later). Instead, I only get the 'connected successfully' message at the end. I don't get any errors or other negative indicators from my server or client.
Any ideas of why io.sockets.socket(userID).emit() doesn't work or what to use in its place?

Socket.io has the concept of rooms where, once a socket has joined a room, it will receive all message sent to a room, so you don't need to track who's in the room, deal with disconnections, etc...
On connection, you'd use:
socket.join('room')
And to send a message to everyone in that room:
io.sockets.in('room').emit('event_name', data)
More info on the socket.io wiki: https://github.com/LearnBoost/socket.io/wiki/Rooms

Try
users.push(socket); // without .sessionId
for (var u in users) {
// users[u] is now the socket
console.log(users[u].id);
users[u].emit('message', { msg: 'New User Connected succesfully' });
}

You can now also use ...
io.to('room').emit('event_name', data);
as an alternative to io.sockets.in

Related

Node.js emit not working on specific socket.on

I'm trying to send news to my client. On connect, it works great, but for some reason on broadcast2 it wont get any response client sided, even know its the same piece of code, and even that broadcast2's console.log is working.
Q: How can i make sure broadcast2 emit will work?
This works:
socket.on('message', function (data) {
console.log('message gotten');
socket.emit('news', { message: 'xxxx' });
});
this wont work:
socket.on('broadcast2', function (data) {
console.log("broadcast revieced");
socket.emit('news', { message: 'xxxx' });
});
this is node.js response:
total code in node.js
socket.on('message', function (data) {
console.log('message gotten');
});
socket.on('another-message', function (data) {
socket.emit('not-news', { hello: 'world' });
});
socket.on('broadcast2', function (data) {
console.log("broadcast revieced");
socket.emit('news', { message: 'xxxx' });
});
and this on the client side:
var socket = io.connect('mysite:8080');
function sender() {
console.log('sending tester');
socket.emit('sendertester', 2);
}
socket.on('connect',function(){
});
socket.on('tester', function(msg){
console.log("callback");
});
socket.on('news', function(message) {
console.log("INCOMMING NEWS");
console.log(message);
});
UPDATE 1:
The broadcast2 socket, sent by PHP:
function broadcast($message,$broadcast = 'broadcast2') {
$client = new Client(new Version1X('myurlhidden:8080'));
$client->initialize();
$client->emit($broadcast, ['message' => $message]);
$client->close();
}
UPDATE 2:
**Question two: Cause my broadcast2 is sent before the client sided is loaded, and then the client connects to the node, could that be the cause?
But in the same time, im already preloading the class that holds the broadcast2 emitter.
Using codeigniter framework.**
UPDATE 3
I was trying to check my theory on update 2, by having two users logged in, while user one trying to perform the trigger. user two gets no output, so i suppose that theory is busted.
The server cannot send a message to any socket before it is connected. You have to wait until you have something listening to receive what you are sending.
I wouldn't call close after the emit either, as you may close the connection before the client has received the message, emit doesn't wait for the client to receive the data before returning its asynchronous.
Instead let the clients close the connections when they terminate.

Maintain socketio conection to each new tab opened by the same user

I'm making an application for our website where users can send chat messages with each other. I've managed to do this successfully using nodejs and socketio. I have a header with some sort of notification icon just like facebook that can be seen in all the pages. Now if the user opens multiple tabs and he receives a message, then all open tabs should see the icon light up. I've gotten this to work by tracking the socket connections opened by users through a 2D array of sockets:
var container = {};
io.sockets.on( 'connection', function(client) {
client.on('set account online', function(username) {
if (!(username in container)) {
console.log(username + " is now Online" );
container[username] = [];
}
client.username = username;
container[username].push(client);
});
client.on('set account offline', function(username) {
if (username in container) {
delete container[username];
console.log(username + " is now Offline" );
}
});
And then when a message is sent I iterate through the appropriate array element
client.on('send message', function(data) {
if (data.recipient in container) {
var clients = container[data.recipient];
for(var i = 0; i < clients.length;i++){
clients[i].emit('send message', {recipient: data.recipient, message: data.message });
}
}
});
That's working well and all (not sure how well coded it is though). The problem is if the user closes a tab, the socket for that tab still exists in the container variable and node would still try to emit to that socket if a message is received for that particular user. Also it just feels cleaner to un-track any disconnected socket.
I've been thinking about this and I think I have to tie the socket disconnect event to the client side's onbeforeunload event and we all know how that performs across different browsers. Any suggestion regarding what's the proper way to splice off disconnected sockets from the container array?
As per my comment:
You should really be implementing rooms. On each connection each user
should join their own room, any additional connections from the same
user should join this room. You can then emit data to the room and
each client inside it will receive the data.
Your code can be changed to:
io.sockets.on('connection', function(client) {
client.on('set account online', function(username) {
client.join(username);
});
client.on('set account offline', function(username) {
client.leave(username);
});
client.on('send message', function(data) {
io.to(data.recipient).emit('send message', {
recipient: data.recipient,
message: data.message
});
});
});

Using Socket.io, how do I detect when a new channel/room has been created?

From the server, I want to be able to detect when a client creates new a room or channel. The catch is that the rooms and channels are arbitrary so i don't know what they will be until the user joins/subscribes. Something like this:
Server:
io.on('created', function (room) {
console.log(room); //prints "party-channel-123"
});
Client:
socket.on('party-channel-123', function (data) {
console.log(data)
})
I also can't have any special client requirements such as sending a message when the channel is subscribed as such:
socket.on('party-channel-123', function (data) {
socket.emit('subscribed', 'party-channel-123');
})
Server:
io.sockets.on('connection', function(socket) {
socket.on('createRoom', function(roomName) {
socket.join(roomName);
});
});
Client
var socket = io.connect();
socket.emit('createRoom', 'roomName');
the io object has references to all currently created rooms and can be used as such:
io.sockets.in(room).emit('event', data);
Hope this helps.
PS. I know its emitting the 'createRoom' that you probably don't want but this is how socket.io is used, this is pretty much copy/paste out of the docs. There are tons of examples on the socket.io website and others.

socket.io send packet to sender only

I have yet to figure out how to directly respond to only the sender using socket.io
I have learned that io.sockets.emit sends to all clients but I wont to send information back to the sender.
code:
socket.on('login', function (data) {
db.users.find({username: cc.lowerCase(data.username)}, function(err, users) {
if (users.length > 0) {
users.forEach( function(user) {
console.log(user.length);
if (user.password == data.password) {
io.sockets.emit('login', { username: user.username });
} else {
io.sockets.emit('error', { message: "Wrong username or password!" });
}
});
} else {
io.sockets.emit('error', { message: "Wrong username or password!" });
}
});
});
When your server listens, you usually get a socket at the "connection" event :
require('socket.io').on('connect', function(socket){
A socket connects 2 points : the client and the server. When you emit on this socket, you emit to this specific client.
Example :
var io = require('socket.io');
io.on('connect', function(socket){
socket.on('A', function(something){
// we just received a message
// let's respond to *that* client :
socket.emit('B', somethingElse);
});
});
Be careful that those are two different calls :
socket.emit : emit to just one socket
io.sockets.emit : emit to all sockets
Simple example
The syntax is confusing in socketio. Also, every socket is automatically connected to their own room with the id socket.id (this is how private chat works in socketio, they use rooms).
Send to the sender and noone else
socket.emit('hello', msg);
Send to everyone including the sender(if the sender is in the room) in the room "my room"
io.to('my room').emit('hello', msg);
Send to everyone except the sender(if the sender is in the room) in the room "my room"
socket.broadcast.to('my room').emit('hello', msg);
Send to everyone in every room, including the sender
io.emit('hello', msg); // short version
io.sockets.emit('hello', msg);
Send to specific socket only (private chat)
socket.broadcast.to(otherSocket.id).emit('hello', msg);
late but better than never ;)
I had smth like this:
io.on('connection', function(socket){
socket.emit('some event', data);
socket.on('private event', function(message){
this.emit('other private event', message);
}
}
After some testing, I realized that 'this.emit' inside 'private event' closure send back only to sender. So i tried 'this.broadcast.emit', which send the message to all connected except the sender. I believe this is what you want from your code.

socket.io create dynamic room

I have been googling for 2 days on my problem to dynamically create rooms on socket.io using nodeJs. When I create a room to the server, I make it like this:
socket.on('follow_me', function (user_id) { //I use the user_id of the user to create room
socket.join(user_id);
console.log(server.sockets.manager.rooms);
});
If next, I want to send a message to all persons connected in the by using
socket.join(user_id);
when i use :
socket.on('message', function (data) {
socket.broadcast.to(data.room).emit('recieve',data.message); //emit to 'room' except this socket
});
The other users in this room do not receive the message; but if I use:
socket.join(user_id);`,when i use :
socket.on('message', function (data) {
socket.broadcast.emit('recieve',data.message);
});
all user receive the message. Why room do not work for me? I think the code is good!
Tank's
socket.on('message', function (data) {
/*considering data.room is the correct room name you want to send message to */
io.sockets.in(data.room).emit('recieve', data.message) //will send event to everybody in the room while
socket.broadcast.to(data.room).emit('recieve', data.message) //will broadcast to all sockets in the given room, except to the socket which called it
/* Also socket.broadcast.emit will send to every connected socket except to socket which called it */
});
I guess what you need is io.sockets.in

Resources