Table of Contents
socket.io简介
socket server
运行服务器端程序
在index.html中
在client.js中
 
Home Backend Development PHP Tutorial 利用socket.io实现多人聊天室(基于Nodejs)

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

Jun 20, 2016 pm 01:00 PM
Socket

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

socket.io简介

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

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

模块安装

新建一个package.json文件,在文件中写入如下内容:

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

执行完这句,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 id="socket-server">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');
});
Copy after login

运行服务器端程序

node index.js
Copy after login

输出

listening 3000
Copy after login

此时在浏览器中打开localhost:3000会得到这样的结果:

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

app.get('/', function (req, res) {
    "use strict";
    res.end("<h1 id="socket-server">socket server</h1>")
});
Copy after login

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

客户端的实现

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

在index.html中



    <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>


<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>

Copy after login

在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  ,

<h2 id=""> </h2>

<p> </p><p class="item-note"><br></p>
Copy after login
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers Of The Witch Tree - How To Unlock The Grappling Hook
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1670
14
PHP Tutorial
1276
29
C# Tutorial
1256
24
Explain secure password hashing in PHP (e.g., password_hash, password_verify). Why not use MD5 or SHA1? Explain secure password hashing in PHP (e.g., password_hash, password_verify). Why not use MD5 or SHA1? Apr 17, 2025 am 12:06 AM

In PHP, password_hash and password_verify functions should be used to implement secure password hashing, and MD5 or SHA1 should not be used. 1) password_hash generates a hash containing salt values ​​to enhance security. 2) Password_verify verify password and ensure security by comparing hash values. 3) MD5 and SHA1 are vulnerable and lack salt values, and are not suitable for modern password security.

PHP and Python: Comparing Two Popular Programming Languages PHP and Python: Comparing Two Popular Programming Languages Apr 14, 2025 am 12:13 AM

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

PHP in Action: Real-World Examples and Applications PHP in Action: Real-World Examples and Applications Apr 14, 2025 am 12:19 AM

PHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.

How does PHP type hinting work, including scalar types, return types, union types, and nullable types? How does PHP type hinting work, including scalar types, return types, union types, and nullable types? Apr 17, 2025 am 12:25 AM

PHP type prompts to improve code quality and readability. 1) Scalar type tips: Since PHP7.0, basic data types are allowed to be specified in function parameters, such as int, float, etc. 2) Return type prompt: Ensure the consistency of the function return value type. 3) Union type prompt: Since PHP8.0, multiple types are allowed to be specified in function parameters or return values. 4) Nullable type prompt: Allows to include null values ​​and handle functions that may return null values.

The Enduring Relevance of PHP: Is It Still Alive? The Enduring Relevance of PHP: Is It Still Alive? Apr 14, 2025 am 12:12 AM

PHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.

PHP and Python: Different Paradigms Explained PHP and Python: Different Paradigms Explained Apr 18, 2025 am 12:26 AM

PHP is mainly procedural programming, but also supports object-oriented programming (OOP); Python supports a variety of paradigms, including OOP, functional and procedural programming. PHP is suitable for web development, and Python is suitable for a variety of applications such as data analysis and machine learning.

How do you prevent SQL Injection in PHP? (Prepared statements, PDO) How do you prevent SQL Injection in PHP? (Prepared statements, PDO) Apr 15, 2025 am 12:15 AM

Using preprocessing statements and PDO in PHP can effectively prevent SQL injection attacks. 1) Use PDO to connect to the database and set the error mode. 2) Create preprocessing statements through the prepare method and pass data using placeholders and execute methods. 3) Process query results and ensure the security and performance of the code.

PHP and Python: Code Examples and Comparison PHP and Python: Code Examples and Comparison Apr 15, 2025 am 12:07 AM

PHP and Python have their own advantages and disadvantages, and the choice depends on project needs and personal preferences. 1.PHP is suitable for rapid development and maintenance of large-scale web applications. 2. Python dominates the field of data science and machine learning.

See all articles