利用socket.io实现多人聊天室(基于Nodejs)

来源:互联网 发布:实时网速监控软件 编辑:程序博客网 时间:2024/05/22 07:02

socket.io简介

在Html5中存在着这样的一个新特性,引入了websocket,关于websocket的内部实现原理可以看这篇文章,这篇文章讲述了websocket无到有,根据协议,分析数据帧的头,进行构建websocket。虽然代码短,但可以很好地体现websocket的原理。

http://blog.csdn.net/newpidian/article/details/50850670

,这个特性提供了浏览器端和服务器端的基于TCP连接的双向通道。但是并不是所有的浏览器都支持websocket特性,故为了磨平浏览器间的差异,为开发者提供统一的接口,引入了socket.io模块。在不支持websoket的浏览器中,socket.io可以降级为其他的通信方式,比如有AJAX long polling ,JSONP Polling等。
模块安装
新建一个package.json文件,在文件中写入如下内容:

{  "name": "socketiochatroom",  "version": "0.0.1",  "dependencies": {    "socket.io": "*",    "express":"*"  }}
npm install 

执行完这句,node将会从npm处下载socket.io和express模块。

    -

服务器端的实现

在文件夹中添加index.js文件,并在文件中写入如下内容:

/** * Created by bamboo on 2016/3/31. */var app = require('express')();var http = require('http').Server(app);var io = require('socket.io')(http);app.get('/', function (req, res) {    "use strict";    res.end("<h1>socket server</h1>")});/*在线人员*/var onLineUsers = {};/* 在线人数*/var onLineCounts = 0;/*io监听到存在链接,此时回调一个socket进行socket监听*/io.on('connection', function (socket) {    console.log('a user connected');    /*监听新用户加入*/    socket.on('login', function (user) {        "use strict";        //暂存socket.name 为user.userId;在用户退出时候将会用到        socket.name = user.userId;        /*不存在则加入 */        if (!onLineUsers.hasOwnProperty(user.userId)) {            //不存在则加入            onLineUsers[user.userId] = user.userName;            onLineCounts++;        }        /*一个用户新加入,向所有客户端监听login的socket的实例发送响应,响应内容为一个对象*/        io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});        console.log(user.userName, "加入了聊天室");//在服务器控制台中打印么么么用户加入到了聊天室    });    /*监听用户退出聊天室*/    socket.on('disconnect', function () {        "use strict";        if (onLineUsers.hasOwnProperty(socket.name)) {            var user = {userId: socket.name, userName: onLineUsers[socket.name]};            delete onLineUsers[socket.name];            onLineCounts--;            /*向所有客户端广播该用户退出群聊*/            io.emit('logout', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});            console.log(user.userName, "退出群聊");        }    })    /*监听到用户发送了消息,就使用io广播信息,信息被所有客户端接收并显示。注意,如果客户端自己发送的也会接收到这个消息,故在客户端应当存在这的判断,是否收到的消息是自己发送的,故在emit时,应该将用户的id和信息封装成一个对象进行广播*/    socket.on('message', function (obj) {        "use strict";        /*监听到有用户发消息,将该消息广播给所有客户端*/        io.emit('message', obj);        console.log(obj.userName, "说了:", obj.content);    });});/*监听3000*/http.listen(3000, function () {    "use strict";    console.log('listening 3000');});

运行服务器端程序

node index.js

输出

listening 3000

此时在浏览器中打开localhost:3000会得到这样的结果:
这里写图片描述

原因是在代码中只对路由进行了如下设置

app.get('/', function (req, res) {    "use strict";    res.end("<h1>socket server</h1>")});

服务器端主要是提供socketio服务,并没有设置路由。

客户端的实现

在客户端建立如下的目录和文件,其中json3.min.js可以从网上下载到。
client
- - - client.js
- - - index.html
- - - json3.min.js
- - - style.css

在index.html中

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="format-detection" content="telephone=no"/>    <meta name="format-detection" content="email=no"/>    <title>1301群聊</title>    <link rel="stylesheet" type="text/css" href="./style.css"/>    <script src="http://realtime.plhwin.com:3000/socket.io/socket.io.js"></script>    <script src="./json3.min.js"></script></head><body><div id="loginbox">    <div style="width: 260px;margin: 200px auto;">        输入你在群聊中的昵称        <br/>        <br/>        <input type="text" style="width:180px;" placeholder="请输入用户名" id="userName" name="userName"/>        <input type="button" style="width: 50px;" value="提交" onclick="CHAT.userNameSubmit();"/>    </div></div><div id="chatbox" style="display: none;">    <div style="background: #3d3d3d;height: 28px;width: 100%;font-size: 12px">        <div style="line-height: 28px;color:#fff;">            <span style="text-align: left;margin-left: 10px;">1301群聊</span>            <span style="float: right;margin-right: 10px"><span id="showUserName"></span>|            <a href="javascript:;" onclick="CHAT.logout()" style="color: #fff;">退出</a></span>        </div>    </div>    <div id="doc">        <div id="chat">            <div id="message" class="message">                <div id="onLineCounts"                     style="background: #EFEFF4; font-size: 12px;margin-top: 10px;margin-left: 10px;color: #666;">                </div>            </div>            <div class="input-box">                <div class="input">                    <input type="text" maxlength="140" placeholder="输入聊天内容 " id="content" name="content" >                </div>                <div class="action">                    <button type="button" id="mjr_send" onclick="CHAT.submit();">提交</button>                </div>            </div>        </div>    </div></div><script type="text/javascript" src="./client.js"></script></body></html>

在client.js中

/** * Created by bamboo on 2016/3/31. */ /*即时运行函数*/(function () {    "use strict";    var d = document,        w = window,        dd = d.documentElement,        db = d.body,        dc = d.compatMode === "CSS1Compat",        dx = dc ? dd : db,        ec = encodeURIComponent,        p = parseInt;    w.CHAT = {        msgObj: d.getElementById("message"),        screenHeight: w.innerHeight ? w.innerHeight : dx.innerHeight,        userName: null,        userId: null,        socket: null,        /*滚动条始终在最底部*/        scrollToBottom: function () {            w.scrollTo(0, this.msgObj.clientHeight);        },        /*此处仅为简单的刷新页面,当然可以做复杂点*/        logout: function () {           // this.socket.disconnect();            w.top.location.reload();        },        submit: function () {            var content = d.getElementById('content').value;            if (content != '') {                var obj = {                    userId: this.userId,                    userName: this.userName,                    content: content                };                //如在服务器端代码所说,此对象就行想要发送的信息和发送人组合成为对象一起发送。                this.socket.emit('message', obj);                d.getElementById('content').value = '';            }            return false;        },        /**客户端根据时间和随机数生成ID,聊天用户名称可以重复*/        genUid: function () {            return new Date().getTime() + "" + Math.floor(Math.random() * 889 + 100);        },        /*更新系统信息        主要是在客户端显示当前在线人数,在线人列表等,当有新用户加入或者旧用户退出群聊的时候做出页面提示。*/        updateSysMsg: function (o, action) {            var onLineUsers = o.onLineUsers;            var onLineCounts = o.onLineCounts;            var user = o.user;            //更新在线人数            var userHtml = '';            var separator = '';            for (var key in onLineUsers) {                if (onLineUsers.hasOwnProperty(key)) {                    userHtml += separator + onLineUsers[key];                    separator = '、';                }            }            //插入在线人数和在线列表            d.getElementById('onLineCounts').innerHTML = '当前共有' + onLineCounts + "在线列表: " + userHtml;            //添加系统消息            var html = '';            html += '<div class="msg_system">';            html += user.userName;            html += (action === "login") ? "加入了群聊" : "退出了群聊";            html += '</div>';            var section = d.createElement('section');            section.className = 'system J-mjrlinkWrap J-cutMsg';            section.innerHTML = html;            this.msgObj.appendChild(section);            this.scrollToBottom();        },        /*用户提交用户名后,将loginbox设置为不显示,将chatbox设置为显示*/        userNameSubmit: function () {            var userName = d.getElementById('userName').value;            if (userName != '') {                d.getElementById('userName').value = '';                d.getElementById('loginbox').style.display = 'none';                d.getElementById('chatbox').style.display = 'block';                this.init(userName);//调用init方法            }            return false;        },        //用户初始化        init: function (userName) {            //随机数生成uid            this.userId = this.genUid();            this.userName = userName;            d.getElementById('showUserName').innerHTML = this.userName;//[newpidian]|[退出]            this.scrollToBottom();            //连接socketIO服务器,newpidian的IP地址            this.socket = io.connect('192.168.3.155:3000');            //向服务器发送某用户已经登录了            this.socket.emit('login', {userId: this.userId, userName: this.userName});            //监听来自服务器的login,即在客户端socket.emit('login ')发送后,客户端就会收到来自服务器的            // io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});            /*监听到有用户login了,更新信息*/            this.socket.on('login', function (o) {                //更新系统信息                CHAT.updateSysMsg(o, 'login');            });            /*监听到有用户logout了,更新信息*/            this.socket.on('logout', function (o) {                CHAT.updateSysMsg(o, 'logout');            });            //var obj = {            //    userId: this.userId,            //    userName: this.userName,            //    content: content            //};            /*监听到有用户发送消息了*/            this.socket.on("message", function (obj) {                //判断消息是不是自己发送的                var isMe = (obj.userId === CHAT.userId);                var contentDiv = '<div>' + obj.content + '</div>';                var userNameDiv = '<span>' + obj.userName + '</span>';                var section = d.createElement('section');                if (isMe) {                    section.className = 'user';                    section.innerHTML = contentDiv + userNameDiv;                } else {                    section.className = 'service';                    section.innerHTML = userNameDiv + contentDiv;                }                CHAT.msgObj.appendChild(section);                CHAT.scrollToBottom();            });        }    }    /*控制键键码值(keyCode)     按键 键码  按键  键码  按键  键码  按键  键码     BackSpace  8   Esc 27  Right Arrow 39  -_  189     Tab    9   Spacebar    32  Dw Arrow    40  .>  190     Clear  12  Page Up 33  Insert  45  /?  191     Enter  13  Page Down   34  Delete  46  `~ 192     Shift  16  End 35  Num Lock    144 [{  219     Control    17  Home    36  ;:  186 \|  220     Alt    18  Left Arrow  37  =+  187 ]}  221     Cape Lock  20  Up Arrow    38  ,<  188 '"  222     * */    //通过“回车键”提交用户名    d.getElementById('userName').onkeydown = function (e) {        console.log(e);        e = e || event;        if (e.keyCode === 13) {            CHAT.userNameSubmit();        }    };    //通过“回车键”提交聊天内容    d.getElementById('content').onkeydown = function (e) {        e = e || event;        if (e.keyCode === 13) {            CHAT.submit();        }    };})();

style.css

秘密

运行结果

服务器端已经运行,现将客户端也运行起来得到下图:

这里写图片描述

添加了new和pidian两个用户,并发送信息和进行退出,得到下面的结果:

这里写图片描述

0 0
原创粉丝点击