2
votes

I am trying to build a chat server and client using node and socket.io following a tutorial from a book.The front-end code is as follows:

<html>
<head>
    <title>Socket.IO example application</title>
    <style type = "text/css">
    #input {
        width: 200px;
    }
    #messages {
        position: fixed;
        top: 40px;
        bottom: 8px;
        left: 8px;
        right: 8px;
        border: 1px solid #EEEEEE;
        padding: 8px;
    }
    </style>
</head>
<body>
    Your message:
    <input id = "input" type = "text" />
    <div id = "messages"></div>
    <script src = "http://localhost:4001/socket.io/socket.io.js"></script>
    <script type = "text/javascript">
    var messagesElement = document.getElementById('messages');
    var lastMessageElement = null;

    function addMessage (message) {
        var newMessageElement = document.createElement('div');
        var newMessageText = document.createTextNode(message);

        newMessageElement.appendChild(newMessageText);
        messagesElement.insertBefore(newMessageElement, lastMessageElement);
        lastMessageElement = newMessageElement;
    }

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

    socket.on('login', function() {
        var username = prompt('What username would you like to use?');
        socket.emit('login', username);
    });

    socket.on('serverMessage', function (content) {
        addMessage(content);
    });

    function sendCommand(command, args) {
        if(command === 'j') {
            socket.emit('join', args);
        } else {
            alert('unknown command: ' + command);
        }
    }

    function sendMessage(message) {
        var commandMatch = message.match(/^\/(\w*)(.*)/);
        if(commandMatch) {
            sendCommand(commandMatch[1], commandMatch[2].trim());
        } else {
            socket.emit('clientMessage', message);
        }
    }

    var inputElement = document.getElementById('input');

    inputElement.onkeydown = function(keyboardEvent) {
        if(keyboardEvent.keyCode === 13) {
            sendMessage(inputElement.value);
            inputElement.value = '';
            return false;
        } else {
            return true;
        }
    };
    </script>
</body>
</html>

And back-end is:

/*jslint node: true */
var httpd = require('http').createServer(handler);
var io = require('socket.io').listen(httpd);
var fs = require('fs');

function handler(req, res) {
    "use strict";
    fs.readFile(__dirname + '/index.html', function (err, data) {
        if (err) {
            res.writeHead(500);
            return res.end('Error Loading index.html');
        }

        res.writeHead(200);
        res.end(data);
    });
}

httpd.listen(4001);

io.sockets.on('connection', function (socket) {
    "use strict";
    socket.on('login', function(username) {
        socket.set('username', username, function (err) {
            if (err) {
                throw err;
            }
            socket.emit('serverMessage', 'Currently logged in as ' + username);
            socket.broadcast.emit('serverMessage', 'User ' + username + ' logged in');
        });
    });

    socket.on('clientMessage', function (content) {
        socket.emit('serverMessage', 'You said: ' + content);
        socket.get('username', function (err, username) {
            if (!username) {
                username = socket.id;
            }
            socket.get('room', function (err, room) {
                if (err) {
                    throw err;
                }
                var broadcast = socket.broadcast,
                    message = content;
                if (room) {
                    broadcast.to(room);
                }
                broadcast.emit('serverMessage', username + ' said: ' + message);
            });
        });
    });

    socket.on('join', function (room) {
        socket.get('room', function (err, oldRoom) {
            if (err) {
                throw err;
            }
            socket.set('room', room, function (err) {
                if (err) {
                    throw err;
                }
                socket.join(room);
                if (oldRoom) {
                    socket.leave(oldRoom);
                }
                socket.get('username', function (err, username) {
                    if (!username) {
                        username = socket.id;
                    }
                    socket.emit('serverMessage', 'You joined room' + room);
                });
                socket.get('username', function (err, username) {
                    if (!username) {
                        username = socket.id;
                    }
                    socket.broadcast.to(room).emit('serverMessage', 'User ' + username + ' joined this room');
                });
            });
        });
    });

    socket.on('disconnect', function() {
        socket.get('username', function (err, username) {
            if (!username) {
                username = socket.id;
            }
            socket.broadcast.emit('serverMessage', 'User ' + username + ' disconnected');
        });
    });

    socket.emit('login');
});

The problem I am facing is that whenever a new user logs in, all the previous users get a message saying "User " + randomID + "disconnected" before the new user logs in and it functions normally. This problem does not occur if a new user logs in quickly after the immediately previous user logged in (I'm guessing it has something to do with heartbeat here). I'd really appreciate any help in figuring out why this disconnect event is being triggered every time a new user logs in. Thanks.

2
I cannot reproduce the problem you mention. - Shubham Goyal

2 Answers

2
votes

alert or prompt in javascript are blocking functions, they stop all javascript events on browsers.

That is why the 'heart' inside socket.io stops beating.

In more detail:

In every heartbeat, the server sends a packet to the clients for checking if the clients are alive or dead, and if a client is not responsive, the server thinks it is dead.

The solution is replacing prompt function with async function, a popup div, form, etc...

0
votes

i have been copy your code,and run in my server,i can't find your problem what your are facing,but i find a problem, when i cancel the usename input window,my user name is null, i find my userid is random string. when i disconnect, socket.io will boardcast a message like that,

"User " + randomID + "disconnected"