Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node.js / socket.io - keep track of clients

Dear friends I have a small issue while trying to keep track of a logged in users in chat. The chat is based on two separate channels that work with the help of namespaces:

  1. chatInfra - to handle logged in users and send welcome messages.
  2. chatCom - to handle messageing between users.

I have searched a lot but I found only theoretical explanations that the best solutions is to store users into array. Therefore I tried to keep the track of logged in users by storing them in array and then iterating through them but still the result is not good.

The problem is that after entering to the chat, only the first logged in user's name appears on screen, whereas the second user's name is not visible.

This is my server side code, I am trying to store users into clients array:

    var clients = [];

    var chatInfra = io.of("/chat_infra").on("connection", function(socket){
        socket.on("set_name", function (data) {
          clients.push(data.name);
          socket.emit('name_set', data);
          socket.send(JSON.stringify({
             type:'serverMessage',  
             message:'Welcome!' 
         }));
        socket.broadcast.emit('user_entered', data);
        });
    });

    var chatCom = io.of("/chat_com").on("connection", function (socket) {
        socket.on('message', function (message) {
            message = JSON.parse(message);
            for(var key in clients){

               if(message.type == "userMessage"){
                  message.username = clients[key];
                  console.log('message : ', message);
                  socket.broadcast.send(JSON.stringify(message));
                  message.type = "myMessage";
                  socket.send(JSON.stringify(message));
               }
            }

        });
    });

Here is how it looks in browser: http://screencast.com/t/lshnfcGZ8E8

Here is the full code: https://gist.github.com/johannesMatevosyan/0b9f7e588338dbb6b7f5

like image 926
johannesMatevosyan Avatar asked Feb 18 '16 17:02

johannesMatevosyan


People also ask

How do I monitor Socket.IO traffic?

Use Monitor.io to observe connections and replay messages It shows a list of active Socket.io client connections for your application. You can use the monitoring interface to broadcast messages–either globally or to a specific client.

How do you check if socket IO client is connected or not?

You can check the socket. connected property: var socket = io. connect(); console.

Is Socket.IO better than WebSocket?

Socket.IO is way more than just a layer above WebSockets, it has different semantics (marks messages with name), and does failovers to different protocols, as well has heartbeating mechanism. More to that attaches ID's to clients on server side, and more. So it is not just a wrapper, it is full-featured library.


1 Answers

I think you're creating an unnecessary overkill by using different namespaces. Here's a clearer working example achieving the same functionality:

server.js

var app    = require("express")();
var server = require("http").Server(app);
var io     = require("socket.io")(server);

var chat = io.of("/chat").on("connection", function(socket){

    socket.on("set_name", function (data) {

        socket.username = data.name;

        socket.emit("name_set", data);
        socket.emit("message", {
            type    :"serverMessage",
            message :"Welcome!" 
        });
        chat.emit("message", {
            type    :"serverMessage",
            message : data.name + " has joined the room.!"
        });
    });

    socket.on("message", function (message) {
        message.username = socket.username;
        chat.emit("message", message);
    });
});


app.get("/", function (req, res) {
    res.sendfile(__dirname + "/index.html");
});

server.listen(3000);

client.js

var socket = io.connect('http://localhost:3000/chat');

socket.on('name_set', function (data) {
    $('#nameform').hide();
    $('#messages').append('<div class="systemMessage">Hello ' + data.name + '</div>');
});

socket.on('message', function (message) {
    var userNameHtml = message.username ? '<span class="name">' + message.username + ':</span>' : '';
    $('#messages').append('<div class="' + message.type + '">' + userNameHtml + message.message + '</div>');
});

$(function () {

    $('#setname').click(function () {
        socket.emit("set_name", { name: $('#nickname').val() });
    });

    $('#send').click(function () {
        socket.emit("message", {
            message : $('#message').val(),
            type    : 'userMessage'
        });
        $('#message').val('');
    });
});

I don't think you need a separate event handler for user_entered, since you are treating it as a regular message and not doing anything else with the event. Also a couple of things:

  • You don't need to first connect to the server and then to the namespace address, connecting to the later is just fine.
  • Don't set event listeners within callbacks, that will result in setting them multiple times.
like image 88
cviejo Avatar answered Oct 23 '22 14:10

cviejo