Node学习入门篇(二):socket.io实现即时通讯

项目结构

这里写图片描述

前端

  • html
<!DOCTYPE html>
<html>
<head>
  <title>chat</title>
  <link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<div id="content">
  <div id="room"></div>
  <div id="room-list"></div>
  <div id="messages"></div>

  <form id="send-form">
    <input id="send-message">
    <input type="submit" value="Send" id="send-button">
    <div id="help">
      Chat commands:
      <ul>
        <li>Change nickname:<code>/nick{username}</code></li>
        <li>Join/create room:<code>/join{room name}</code></li>
      </ul>
    </div>
  </form>
</div>

<script type="text/javascript" src='/socket.io/socket.io.js'></script>
<script type="text/javascript" src='http://code.jquery.com/jquery-1.8.0.min.js'></script>
<script type="text/javascript" src='/javascripts/chat.js'></script>
<script type="text/javascript" src='/javascripts/chat_ui.js'></script>
</body>
</html>
  • CSS
body {
  padding: 50px;
  font:14px 'Lucida Grande'. Helvetica, Arial. sans-serif;
}

a {
  color: #00B7FF;
}

#content {
  width: 800px;
  margin-left: auto;
  margin-right: auto;
}

#room {
  background-color: #ddd;
  margin-bottom: 1em;
}

#messages {
  width: 690px;
  height: 300px;
  overflow: auto;
  background-color: #eee;
  margin-bottom: 1em;
  margin-right: 10px;
}

#room-list{
  float: right;
  width: 100px;
  height: 300px;
  overflow: auto;
}

#room-list div {
  border-bottom: 1px solid #eee;
}

#room-list div:hover {
  background-color: #ddd;
}

#send-message {
  width: 700px;
  margin-bottom: 1em;
  margin-right: 1em;
}

#help {
  font:10px 'Lucida Grande'. Helvetica, Arial. sans-serif;
}
  • JS

chat.js

var Chat = function(socket) {
    this.socket = socket;
};

Chat.prototype.sendMessage  = function(room, text){ 
    var message = {
        room:room,
        text:text
    };

    this.socket.emit('message', message);
};

Chat.prototype.changeRoom = function(room){
    this.socket.emit('join', {
        newRoom:room
    });
};

Chat.prototype.processCommand = function(command){
    var words = command.split(' ');
    var command = words[0].substring(1, words[0].length).toLowerCase();
    var message = false

    switch (command) {
        case 'join':
            words.shift();
            var room = words.join(" ");
            this.changeRoom(room);
            break;
        case 'nick':
            words.shift();
            var name = words.join(' ');
            this.socket.emit('nameAttempt', name);
            break;
        default:
            message = 'Unrecognized command.';
            break;
    }
    return message;
};

chat_ui.js

function divEscapedContentElement(message) {
    return $('<div></div>').text(message);
}

function divSystemContentElement(message) {
    return $('<div></div>').html('<i>' + message + '</i>');
}

function processUserInput(chatApp, socket) {
    var message = $('#send-message').val();
    var  systemMessage;

    if (message.charAt(0) == '/') {
        systemMessage = chatApp.processCommand(message);
        if (systemMessage) {
            $('#messages').append(divSystemContentElement(systemMessage));
        }
    } else {
        chatApp.sendMessage($('#room').text(), message);
        $('#messages').append(divEscapedContentElement(message));
        $('#messages').scrollTop($('#messages').prop('scrollHeight'));
    }
    $('#send-message').val('');
}

var socket = io.connect();

$(document).ready(function() {
    var chatApp = new Chat(socket);

    console.log(socket);
    socket.on('nameResult', function(result) {

        var message;
        if (result.success) {
            message = 'you are now knowd as ' + result.name + '.';
        } else {
            message = result.message;
        }
        $('#messages').append(divSystemContentElement(message));
    });

    socket.on('joinResult', function(result) {

        $('#room').text(result.room);
        $('#messages').append(divSystemContentElement('Room Changed'));

    });

    socket.on('message', function(message) {

        var newElement = $('<div></div>').text(message.text);
        $('#messages').append(newElement);
    });

    socket.on('rooms', function(rooms) {

        $('#room-list').empty();
        for(var room in rooms) {
            room = room.substring(1, room.length);
            if (room != '') {
                $('#room-list').append(divEscapedContentElement(room));
            }
        }

        $('#room-list div').click(function() {
            chatApp.processCommand('/join' + $(this).text());
            $('#send-message').focus();
        });
    });

    setInterval(function() {
        socket.emit('rooms');

    }, 1000);

    $('#send-message').focus();
    $('#send-form').submit(function() {
        processUserInput(chatApp, socket);
        return false;
    });
});

服务端

app.js

var http = require('http');
var fs = require('fs');
var path = require('path');
var mime = require('mime');
var cache = {};
var chatServer = require('./lib/chat_server')
var server = http.createServer(function(req,res) {
    var filePath = '';
    if(req.url == '/') {
        filePath = 'public/index.html';
    } else {
        console.log(req.url);
        filePath = 'public' + req.url;
    }
    var absPath = './' + filePath;
    console.log(absPath);
    serverStatic(res, cache, absPath);
});
server.listen(3000, function () {
    console.log('localhost:3000...');
});

chatServer.listen(server);

function send404(res) {
    res.writeHead(404,{'content-type':'text/plain'});
    res.write('Error:404:resource not found');
    res.end();
}

function sendFile(res, filepath, fileContents) {
    res.writeHead(200,{
        'content-type':mime.lookup(path.basename(filepath))
    });
    res.end(fileContents);
}

function serverStatic(res, cache, absPath) {
    if (cache[absPath]) {
        sendFile(res, absPath, cache[absPath]);
    } else {
        fs.exists(absPath, function(exits) {
            if(exits) {
                fs.readFile(absPath, function(err, data) {
                    if (err) {
                        send404(res);
                    } else {
                        cache[absPath] = data;
                        sendFile(res, absPath, data);
                    }
                });                
            } else {
                send404(res);
            }
        });
    }
}

chat_server.js

var socketio = require('socket.io');
var io;
var guestNumber = 1;
var nickNames = {};
var namesUsed = [];
var currentRoom = {};

exports.listen = function (server) {
    io = socketio.listen(server);
    io.set('log level', 1);
    io.sockets.on('connection', function (socket) {
        guestNumber = assignGuestName(socket, guestNumber, nickNames, namesUsed);
        joinRoom(socket, 'Lobby');
        handleMessageBroadcasting(socket, nickNames);
        handleNameChangeAttempts(socket, nickNames, namesUsed);
        handleRoomJoining(socket);

        socket.on('rooms', function () {
            socket.emit('rooms', io.sockets.manager.rooms);
        });
      handleClientDisconnection(socket, nickNames, namesUsed);  
    });
};

function assignGuestName(socket, guestNumber, nickNames, namesUsed) {
    var name = 'Guest' + guestNumber;
    nickNames[socket.id] = name;
    socket.emit('nameResult',{
        success:true,
        name:name
    });
    namesUsed.push(name);
    return guestNumber + 1;
}

function joinRoom(socket, room) {
    socket.join(room);
    currentRoom[socket.id] = room;

    socket.emit('joinResult',{
        room:room
    });
    socket.broadcast.to(room).emit('message', {
        text:nickNames[socket.id] + ' has joined ' + room + '.'
    });

    var usersInRoom = io.sockets.clients(room);
    if (usersInRoom.length > 1 ) {
        var usersInRoomSummary = 'Users currently in ' + room +":";
        for(var index  in usersInRoom) {
            var userSocketId = usersInRoom[index].id;
            if (userSocketId != socket.id) {
                if (index > 0) {
                    usersInRoomSummary += ',';
                }
                usersInRoomSummary += nickNames[userSocketId];
            }
        }
        usersInRoomSummary += '.';
        socket.emit('message', {text:usersInRoomSummary});
    }
}

function handleNameChangeAttempts(socket, nickNames, namesUsed) {
    socket.on('nameAttempt', function(name) {
        if (name.indexOf('Guest') == 0 ) {
            socket.emit('nameResult', {
                success:false,
                message:'Names cannot begin with "Guest".'
            });
        } else {

            if (namesUsed.indexOf(name) == -1) {
                var prename = nickNames[socket.id];
                var prenameindex = namesUsed.indexOf(prename);
                namesUsed.push(name);
                nickNames[socket.id] = name;
                delete namesUsed[prenameindex];
                socket.emit('nameResult', {
                    success:true,
                    name:name
                });

                socket.broadcast.to(currentRoom[socket.id]).emit('message', {
                    text:prename + " is now known as " + name + '.'
                });

            } else {
                socket.emit('nameResult', {
                    success: false,
                    message:'That name is already in use.'
                });
            }
        }
    });
}

function handleMessageBroadcasting(socket,nickNames) {
    socket.on('message', function (message) {
        socket.broadcast.to(message.room).emit('message', {
            text:nickNames[socket.id] + ':' + message.text
        });
    });
}

function handleRoomJoining(socket) {
    socket.on('join', function(room) {
        socket.leave(currentRoom[socket.id]);
        joinRoom(socket, room.newRoom);
    });
}

function handleClientDisconnection(socket) {
    socket.on('disconnect', function() {
        var nameIndex = namesUsed.indexOf(nickNames[socket.id]);
        delete namesUsed[nameIndex];
        delete nickNames[socket.id];
    })
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值