zoukankan      html  css  js  c++  java
  • 利用socket.io实现多人聊天室(基于Nodejs)

    socket.io简单介绍

    在Html5中存在着这种一个新特性。引入了websocket,关于websocket的内部实现原理能够看这篇文章。这篇文章讲述了websocket无到有,依据协议,分析数据帧的头,进行构建websocket。尽管代码短。但能够非常好地体现websocket的原理。
    

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

    ,这个特性提供了浏览器端和server端的基于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模块。

      -

    server端的实现

    在文件夹中增加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++;
            }
            /*一个用户新增加,向全部client监听login的socket的实例发送响应,响应内容为一个对象*/
            io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
            console.log(user.userName, "增加了聊天室");//在server控制台中打印么么么用户增加到了聊天室
        });
        /*监听用户退出聊天室*/
        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--;
    
                /*向全部client广播该用户退出群聊*/
                io.emit('logout', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
                console.log(user.userName, "退出群聊");
            }
        })
        /*监听到用户发送了消息。就使用io广播信息。信息被全部client接收并显示。注意。假设client自己发送的也会接收到这个消息,故在client应当存在这的推断。是否收到的消息是自己发送的。故在emit时,应该将用户的id和信息封装成一个对象进行广播*/
        socket.on('message', function (obj) {
            "use strict";
            /*监听到实用户发消息,将该消息广播给全部client*/
            io.emit('message', obj);
            console.log(obj.userName, "说了:", obj.content);
        });
    });
    /*监听3000*/
    http.listen(3000, function () {
        "use strict";
        console.log('listening 3000');
    });
    

    执行server端程序

    node index.js

    输出

    listening 3000

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

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

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

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

    client的实现

    在client建立例如以下的文件夹和文件。当中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=" 260px;margin: 200px auto;">
            输入你在群聊中的昵称
            <br/>
            <br/>
            <input type="text" style="180px;" placeholder="请输入username" id="userName" name="userName"/>
            <input type="button" style=" 50px;" value="提交" onclick="CHAT.userNameSubmit();"/>
        </div>
    </div>
    
    <div id="chatbox" style="display: none;">
        <div style="background: #3d3d3d;height: 28px; 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 }; //如在server端代码所说,此对象即可想要发送的信息和发送人组合成为对象一起发送。 this.socket.emit('message', obj); d.getElementById('content').value = ''; } return false; }, /**client依据时间和随机数生成ID,聊天username称能够反复*/ genUid: function () { return new Date().getTime() + "" + Math.floor(Math.random() * 889 + 100); }, /*更新系统信息 主要是在client显示当前在线人数。在线人列表等,当有新用户增加或者旧用户退出群聊的时候做出页面提示。*/ 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(); }, /*用户提交username后,将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(); //连接socketIOserver,newpidian的IP地址 this.socket = io.connect('192.168.3.155:3000'); //向server发送某用户已经登录了 this.socket.emit('login', {userId: this.userId, userName: this.userName}); //监听来自server的login,即在clientsocket.emit('login ')发送后,client就会收到来自server的 // 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 * */ //通过“回车键”提交username 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

    秘密

    执行结果

    server端已经执行。现将client也执行起来得到下图:

    这里写图片描写叙述

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

    这里写图片描写叙述

  • 相关阅读:

    梯度下降法
    维特比算法
    分治法
    动态规划
    hadoop学习视频
    Java深拷贝浅拷贝
    Android NDK r8 Cygwin CDT 在window下开发环境搭建 安装配置与使用 具体图文解说
    Linux高性能server编程——定时器
    OpenGL进阶演示样例1——动态画线(虚线、实线、颜色、速度等)
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7279657.html
Copyright © 2011-2022 走看看