使用nodeJs+web Socket构建即时通讯(WebIM)

本文介绍了如何使用Node.js和Socket.IO构建一个实时通讯系统,包括聊天室和私聊功能,以及发送图片和表情。通过示例代码展示了服务器端和客户端的实现,并探讨了WebSocket与浏览器兼容性问题的解决方案。此外,还讨论了长连接、长轮询等Web通信概念和技术的优缺点。
摘要由CSDN通过智能技术生成

在文章的开头,我要解释一下,为什么不直接使用web Socket实现即时通讯,因为一部分浏览器并不兼容web Socket,导致即时通讯在这些浏览器上无法正常使用,所以才需要用到nodeJs里封装好webSocket协议的socket.io包模块来提供不兼容websocket浏览器的解决方案并接管客户与服务器端交互的IO流。(一般处理不兼容websocket的浏览器的方法就是考虑 commit 方式,或者用 Flash sockect.)

这个即时通讯的demo包括最基本的聊天室功能和私聊功能,其他附加的功能就是发送图片和表情及改变字体颜色,实现最基本的对话聊天功能。需要其他功能的可以懂得原理后自行添加模块进来。话不多说,直接用代码说话。(其中将会使用到express和socket.io两个包模块,一定要先安装好。PS: express是node.js中管理路由响应请求的模块,根据请求的URL返回相应的HTML页面。这里我们使用一个事先写好的静态页面返回给客户端,只需使用express指定要返回的页面的路径即可。如果不用这个包,我们需要将HTML代码与后台JavaScript代码写在一起进行请求的响应,不太方便。socket.io是Node.js中使用socket的一个包。使用它可以很方便地建立服务器到客户端的sockets连接,发送事件与接收特定事件。)
首先,我们来看服务器端代码:

var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server);
//指定静态HTML文件的位置
app.use('/', express.static(__dirname + '/www'));
server.listen(3000);//监听端口是否有来自客户端的请求

var onlineUsers = {};//在线用户列表
var socketList = {};//每个用户所持有的与服务器交互的socket列表
var onlineCount = 0;//在线人数

//处理socket事件
io.sockets.on('connection', function(socket) {
   
    //新用户登陆
    socket.on('login', function(obj) {
   
        if (onlineUsers.hasOwnProperty(obj.userid)) {
            socket.emit('userExisted');
        } else {
            socket.name = obj.userid;
            socketList[obj.userid] = socket;
            //检查在线用户列表,如果不存在,则将该用户加入在线用户表
            if(!onlineUsers.hasOwnProperty(obj.userid)) {
                onlineUsers[obj.userid] = obj.nickname;
                //在线人数+1
                onlineCount++;
            }
            socket.emit('loginSuccess',{onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
            io.sockets.emit('system', obj, onlineCount, 'login');
        };
    });
    //用户离线
    socket.on('disconnect', function() {
   
        //将退出的用户从在线列表中删除
        if(onlineUsers.hasOwnProperty(socket.name)) {
            //退出用户的信息
            var obj = {userid:socket.name, nickname:onlineUsers[socket.name]};

            //删除
            delete onlineUsers[socket.name];
            delete socketList[socket.name];
            //在线人数-1
            onlineCount--;

            //向所有客户端广播用户退出
            socket.broadcast.emit('system', obj, onlineCount, 'logout');
        }
    });
    //接收新信息
    socket.on('postMsg', function(msg, color) {
   
        socket.broadcast.emit('newMsg', onlineUsers[socket.name], msg, color);
    });
    //接收新私信(P2P)
    socket.on('privateMsg', function(msg, color, userid) {
   
        socketList[userid].emit('newMsg', onlineUsers[socket.name], msg, color);
    });
    //接收新图片
    socket.on('img', function(imgData, color) {
   
        socket.broadcast.emit('newImg', onlineUsers[socket.name], imgData, color);
    });
    //接收新私人图片(P2P)
    socket.on('privateimg', function(imgData, color, userid) {
   
        socketList[userid].emit('newImg', onlineUsers[socket.name], imgData, color);
    });
});

学过JS的小伙伴们肯定都能看得懂大概的意思吧,如果不明白socket.io中的服务器推技术是怎么实现的,可以百度一下相关文档,这里就不多加赘述了。现在我们来看客户端的代码实现:


window.onload = function() {
   
    var rdChat = new RdChat();
    rdChat.init();
};
var RdChat = function() {
   
    this.socket = null;
};
RdChat.prototype = {
    init: function() {
   
        var that = this;
        var userList = {};//用户列表
        var userCount = null;//用户数
        this.socket = io.connect();
        this.socket.on('connect', function() {
   //用户登录
            document.getElementById('info').textContent = 'get yourself a nickname :)';
            document.getElementById('nickWrapper').style.display = 'block';
            document.getElementById('nicknameInput').focus();
        });
        this.socket.on('nickExisted', function() {
   
            document.getElementById('info').textContent = '!nickname is taken, choose another pls';
        });
        this.socket.on('loginSuccess', function(o) {
   
            document.title = 'RdChat | ' + document.getElementById('nicknameInput').value;
            this.userList = o.onlineUsers;
            that._initUserList(o.onlineUsers);
            document.getElementById('loginWrapper').style.display = 'none';
            document.getElementById('messageInput').focus();
        });
        this.socket.on('error', function(err) {
   
            if (document.getElementById('loginWrapper').style.display == 'none') {
                document.getElementById('status').textContent = '!fail to connect :(';
            } else {
                document.getElementById('info').textContent = '!fail to connect :(';
            }
        });
        this.socket.on('system', function(obj, userCount, type) {
   
            var msg = obj.nickname + (type == 'login' ? ' joined' : ' left');
            that._displayNewMsg('system ', msg, 'red');
            if(type == 'login' && !this.userList.hasOwnProperty(obj.userid)){
                that._updateUserList(obj);
            }
            if(document.getElementById('userlist').value == ""){
                document.getElementById('status').textContent = userCount + (userCount > 1 ? ' users' : ' user') + ' online';
            }else{
                if(document.getElementById('userlist').value == obj.userid){
                    document.getElementById('status').textContent = obj.nickname + "  " + type;
                }
            }

        });
        this.socket.on('newMsg', function(user, msg, color) {
   
            that._displayNewMsg(user, msg, color);
        });
        this.socket.on('newImg', function(user, img, color) {
   
            that._displayImage(user, img, color);
        });
        document.getElementById('loginBtn').addEventListener('click', function() {
   //监听登录按钮的click事件
            var nickName = document.getElementById('nicknameInput').value;
            var userid = that._getUid();
            if (nickName.trim().length != 0) {
                that.socket.emit('login', {userid:userid, nickname:nickName});
            } else {
                document.getElementById('nicknameInput').focus();
            };
        }, false);
        document.getElementById('nicknameInput').addEventListener('keyup', function(e) {
   //监听回车键事件
            if (e.keyCode == 13) {
                var nickName = document.getElementById('nicknameInput').value;
                var userid = that._getUid();
                if (nickName.trim().length != 0) {
       
  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值