socket.io(官网:http://socket.io/)是一个跨平台,多种连接方式自动切换,做即时通讯方面的开发很方便,而且能和expressjs提供的传统请求方式很好的结合,即可以在同一个域名,同一个端口提供两种连接方式:request/response, websocket(flashsocket,ajax…). 一个聊天室demo:

  • 多人聊天
  • 单独聊天
  • 上线下线通知
屏幕快照 2014-07-15 11.49.58   项目结构:   屏幕快照 2014-07-15 12.10.32   1.package.json
{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.3.1",
    "socket.io": "*"
  }
}
2.app.js

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

var users = {};//存储在线用户列表的对象

app.get('/', function (req, res) {
  if (req.cookies.user == null) {
    res.redirect('/signin');
  } else {
    res.sendfile('views/index.html');
  }
});
app.get('/signin', function (req, res) {
  res.sendfile('views/signin.html');
});
app.post('/signin', function (req, res) {
  if (users[req.body.name]) {
    //存在,则不允许登陆
    res.redirect('/signin');
  } else {
    //不存在,把用户名存入 cookie 并跳转到主页
    res.cookie("user", req.body.name, {maxAge: 1000*60*60*24*30});
    res.redirect('/');
  }
});

var server = http.createServer(app);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {

  //有人上线
  socket.on('online', function (data) {
    //将上线的用户名存储为 socket 对象的属性,以区分每个 socket 对象,方便后面使用
    socket.name = data.user;
    //users 对象中不存在该用户名则插入该用户名
    if (!users[data.user]) {
      users[data.user] = data.user;
    }
    //向所有用户广播该用户上线信息
    io.sockets.emit('online', {users: users, user: data.user});
  });

  //有人发话
  socket.on('say', function (data) {
    if (data.to == 'all') {
      //向其他所有用户广播该用户发话信息
      socket.broadcast.emit('say', data);
    } else {
      //向特定用户发送该用户发话信息
      //clients 为存储所有连接对象的数组
      var clients = io.sockets.clients();
      //遍历找到该用户
      clients.forEach(function (client) {
        if (client.name == data.to) {
          //触发该用户客户端的 say 事件
          client.emit('say', data);
        }
      });
    }
  });

  //有人下线
  socket.on('disconnect', function() {
    //若 users 对象中保存了该用户名
    if (users[socket.name]) {
      //从 users 对象中删除该用户名
      delete users[socket.name];
      //向其他所有用户广播该用户下线信息
      socket.broadcast.emit('offline', {users: users, user: socket.name});
    }
  });
});

server.listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

3. ./routes/index.js
exports.index = function(req, res){
  res.render('index', { title: 'Express' });
};
4. ./routes/user.js
exports.list = function(req, res){
  res.send("respond with a resource");
};
5. ./views/index.html
 





聊天室








  
你好 ,你正在对
发送
在线用户
    6. ./views/signin.html
     
    
    
    
    
    登陆
    
    
    
    
      
    昵称:
    7. 前端./public/javascript/chat.js
     
    $(document).ready(function() {
        $(window).keydown(function(e) {
            if (e.keyCode == 116) {
                if (!confirm("刷新将会清除所有聊天记录,确定要刷新么?")) {
                    e.preventDefault();
                }
            }
        });
        var socket = io.connect();
        var from = $.cookie('user'); //从 cookie 中读取用户名,存于变量 from
        var to = 'all'; //设置默认接收对象为"所有人"
        //发送用户上线信号
        socket.emit('online', {
            user: from
        });
        socket.on('online',
        function(data) {
            //显示系统消息
            if (data.user != from) {
                var sys = '
    系统(' + now() + '):' + '用户 ' + data.user + ' 上线了!
    '; } else { var sys = '
    系统(' + now() + '):你进入了聊天室!
    '; } $("#contents").append(sys + "
    "); //刷新用户在线列表 flushUsers(data.users); //显示正在对谁说话 showSayTo(); }); socket.on('say', function(data) { //对所有人说 if (data.to == 'all') { $("#contents").append('
    ' + data.from + '(' + now() + ')对 所有人 说:
    ' + data.msg + '

    '); } //对你密语 if (data.to == from) { $("#contents").append('
    ' + data.from + '(' + now() + ')对 你 说:
    ' + data.msg + '

    '); } }); socket.on('offline', function(data) { //显示系统消息 var sys = '
    系统(' + now() + '):' + '用户 ' + data.user + ' 下线了!
    '; $("#contents").append(sys + "
    "); //刷新用户在线列表 flushUsers(data.users); //如果正对某人聊天,该人却下线了 if (data.user == to) { to = "all"; } //显示正在对谁说话 showSayTo(); }); //服务器关闭 socket.on('disconnect', function() { var sys = '
    系统:连接服务器失败!
    '; $("#contents").append(sys + "
    "); $("#list").empty(); }); //重新启动服务器 socket.on('reconnect', function() { var sys = '
    系统:重新连接服务器!
    '; $("#contents").append(sys + "
    "); socket.emit('online', { user: from }); }); //刷新用户在线列表 function flushUsers(users) { //清空之前用户列表,添加 "所有人" 选项并默认为灰色选中效果 $("#list").empty().append('
  • 所有人
  • '); //遍历生成用户在线列表 for (var i in users) { $("#list").append('
  • ' + users[i] + '
  • '); } //双击对某人聊天 $("#list > li").dblclick(function() { //如果不是双击的自己的名字 if ($(this).attr('alt') != from) { //设置被双击的用户为说话对象 to = $(this).attr('alt'); //清除之前的选中效果 $("#list > li").removeClass('sayingto'); //给被双击的用户添加选中效果 $(this).addClass('sayingto'); //刷新正在对谁说话 showSayTo(); } }); } //显示正在对谁说话 function showSayTo() { $("#from").html(from); $("#to").html(to == "all" ? "所有人": to); } //获取当前时间 function now() { var date = new Date(); var time = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + (date.getMinutes() < 10 ? ('0' + date.getMinutes()) : date.getMinutes()) + ":" + (date.getSeconds() < 10 ? ('0' + date.getSeconds()) : date.getSeconds()); return time; } //发话 $("#say").click(function() { //获取要发送的信息 var $msg = $("#input_content").html(); if ($msg == "") return; //把发送的信息先添加到自己的浏览器 DOM 中 if (to == "all") { $("#contents").append('
    你(' + now() + ')对 所有人 说:
    ' + $msg + '

    '); } else { $("#contents").append('
    你(' + now() + ')对 ' + to + ' 说:
    ' + $msg + '

    '); } //发送发话信息 socket.emit('say', { from: from, to: to, msg: $msg }); //清空输入框并获得焦点 $("#input_content").html("").focus(); }); });
    8.运行项目: npm install node app 浏览器访问http://127.0.0.1:3000 源码链接: http://pan.baidu.com/s/1mgohRVM 密码: jj7m