nodejs+websocket实时聊天系统

   2023-02-09 学习力0
核心提示:介绍下websocket:webSocket协议本质上是一个基于tcp的协议;建立一个websocket连接,大体的过程:1.客户端浏览器首先向服务器发起一个http请求,这个请求和平常的请求有什么不同呢?多了一点附加头信息:"upgrade:web Socket” 表明我这申请的是一个websocket

介绍下websocket:

webSocket协议本质上是一个基于tcp的协议;

建立一个websocket连接,大体的过程:

1.客户端浏览器首先向服务器发起一个http请求,这个请求和平常的请求有什么不同呢?

多了一点附加头信息:"upgrade:web Socket” 表明我这申请的是一个websocket的http请求;

2.服务器收到请求后,解析这些附加的头信息,然后产生应答信息返回给客户端,这样,连接就建立了;

3.双方就可以通过这个连接通道***的信息传递,这个连接会一直存在,直到一方自动关闭连接;

 

客户端到服务端:

GET /demo HTTP/1.1

Host: example.com

Connection: Upgrade

Sec-WebSocket-Key2: 12998 5 Y3 1 .P00

Upgrade: WebSocket

Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5

Origin: http://example.com

[8-byte security key]

 

服务端到客户端:

HTTP/1.1 101 WebSocket Protocol Handshake

Upgrade: WebSocket

Connection: Upgrade

WebSocket-Origin: http://example.com

WebSocket-Location: ws://example.com/demo

[16-byte hash response]

 

从客户端到服务端请求的信息里面包含:‘Sec-webSocket-key1","Sec-WebSocket-key2"和“[8-byte security key]”这样的信息;这是客户端浏览器需要向服务端提供的握手信息,服务端解析这些头信息,并且在握手的过程中依据这些信息生成一个16位的安全密钥并返回给客户端,以表明服务器端获取了客户端的请求;

大致步骤:

1.	逐个字符读取 Sec-WebSocket-Key1 头信息中的值,将数值型字符连接到一起放到一个临时字符串里,同时统计所有空格的数量;
2.	将在第 1 步里生成的数字字符串转换成一个整型数字,然后除以第 1 步里统计出来的空格数量,将得到的浮点数转换成整数型;
3.	将第 2 步里生成的整型值转换为符合网络传输的网络字节数组;
4.	对 Sec-WebSocket-Key2 头信息同样进行第 1 到第 3 步的操作,得到另外一个网络字节数组;
5.	将 [8-byte security key] 和在第 3,第 4 步里生成的网络字节数组合并成一个 16 字节的数组;
6.	对第 5 步生成的字节数组使用 MD5 算法生成一个哈希值,这个哈希值就作为安全密钥返回给客户端,以表明服务器端获取了客户端的请求,同意创建 WebSocket 连接

 

 var  wsServer = 'ws://localhost:8888/Demo';  //连接地址
 var  websocket = new WebSocket(wsServer);   //建立连接
 websocket.onopen = function (evt) { onOpen(evt) };  //4个事件
 websocket.onclose = function (evt) { onClose(evt) }; 
 websocket.onmessage = function (evt) { onMessage(evt) }; 
 websocket.onerror = function (evt) { onError(evt) }; 
 function onOpen(evt) { 
 console.log("Connected to WebSocket server."); 
 } 
 function onClose(evt) { 
 console.log("Disconnected"); 
 } 
 function onMessage(evt) { 
 console.log('Retrieved data from server: ' + evt.data); 
 } 
 function onError(evt) { 
 console.log('Error occured: ' + evt.data); 
 }

   浏览器的支持情况:

浏览器	支持情况
Chrome	Supported in version 4+
Firefox	Supported in version 4+
Internet Explorer	Supported in version 10+
Opera	Supported in version 10+
Safari	Supported in version 5+

 正文来了:基于websocket制作的简单聊天系统;

client.html:

 <style>
        .kuang {
            width: 600px;
            min-height: 50px;
            max-height: 296px;
            border: 1px solid;
            float: left;
            display: block;
            position: relative;
            overflow-y: scroll;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
              <div class="jumbotron  bg-dark">
                <h1 class="jumbotron-heading">WebSocket chat,欢迎使用:</h1>
              </div>
            <div class="input-group text-left">
                <label>输入用户名:</label>
                <input type="text"  />
                <button >连接</button>
                <button >断开</button>
            </div>
            <div class="input-group text-muted">
                <div class="kuang" ></div>
            </div>
         <hr class="featurette-divider">
            <div class="input-group text-left">
                <input type="text" class="value"  />
                <button >发送</button>
            </div>
        </div>
    </div>

 简单的界面,大致效果就是这样的:

nodejs+websocket实时聊天系统

然后实现逻辑代码:

 var ws = new WebSocket('ws://127.0.0.1:8082');
                ws.onopen = function (e) {
                    console.log("连接服务器成功");
                }
                ws.onmessage = function (e) {
                    value1.removeAttribute("readOnly");
                    var time = new Date();
                    mess.innerHTML += time.toUTCString() + ":" + e.data + "<br>";
                    document.getElementById("send").onclick = function (e) {
                        ws.send(input.value + "说:" + value1.value);
                        value1.value = " ";
                    }
                    document.onkeydown = function (e) {
                        e = e || window.event;
                        if (e.keyCode == 13) {
                            document.getElementById("send").onclick();
                            return false;
                        }
                    }
                }
                ws.onclose = function (e) {
                    console.log("服务器关闭");
                }
                ws.onerror = function () {
                    console.log("连接出错");
                }

 连接地址:ws://127.0.0.1:8082  那是哪里来的呢?  (注意http请求则是写成http://xxx,https请求则是https://xxx;ws当然是ws://xxx);

wbsocket只是客服端,地址当然是从我们的服务端给的呀;

服务端的搭建采用了一个这样的库:

nodejs-websocket
 
1.npm isntall -g nodejs-websocket
2.在js页面引入它 
var ws = require("nodejs-websocket");
3.创建一个服务
var server = ws.createServer(function (conn) {
    conn.on('text', function (str) {
    })

    conn.on("close", function (code, reason) {
        console.log("关闭连接");
    })
    conn.on("error", function (code, reason) {
        console.log("异常关闭");
    });
}).listen(8082);
console.log("websocket连接完毕")

 好了,websocket连接算是建立啦!

下面展示下具体代码:

client.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="bootstrap-3.3.7-dist/css/bootstrap.min.css" />
    <script src="jquery.min.js"></script>
    <script src="bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    <style>
        .kuang {
            width: 600px;
            min-height: 50px;
            max-height: 296px;
            border: 1px solid;
            float: left;
            display: block;
            position: relative;
            overflow-y: scroll;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row">
              <div class="jumbotron  bg-dark">
                <h1 class="jumbotron-heading">WebSocket chat,欢迎使用:</h1>
              </div>
            <div class="input-group text-left">
                <label>输入用户名:</label>
                <input type="text"  />
                <button >连接</button>
                <button >断开</button>
            </div>
            <div class="input-group text-muted">
                <div class="kuang" ></div>
            </div>
         <hr class="featurette-divider">
            <div class="input-group text-left">
                <input type="text" class="value"  />
                <button >发送</button>
            </div>
        </div>
    </div>
    <script>
        var input = document.getElementById("name");
        var conn = document.getElementById("conn");
        var close = document.getElementById("close");
        var mess = document.getElementById("mess");
        var value1 = document.getElementById("value1");
        var pattern = /^[\u4e00-\u9fa5]{2,10}$/;
        close.disabled = true;
        if (window.WebSocket) {
            conn.onclick = function () {
                if (!pattern.test(input.value)) {
                    alert("名称不能为空且必须为中文");
                    return;
                }
                var ws = new WebSocket('ws://127.0.0.1:8082');
                conn.disabled = true;
                close.disabled = false;
                ws.onopen = function (e) {
                    console.log("连接服务器成功");
                    ws.send(input.value);
                    input.setAttribute("readOnly", 'true');
                    value1.setAttribute("readOnly", 'true');
                }
                ws.onmessage = function (e) {
                    value1.removeAttribute("readOnly");
                    var time = new Date();
                    mess.innerHTML += time.toUTCString() + ":" + e.data + "<br>";
                    document.getElementById("send").onclick = function (e) {
                        ws.send(input.value + "说:" + value1.value);
                        value1.value = " ";
                    }
                    document.onkeydown = function (e) {
                        e = e || window.event;
                        if (e.keyCode == 13) {
                            document.getElementById("send").onclick();
                            return false;
                        }
                    }
                }
                ws.onclose = function (e) {
                    console.log("服务器关闭");
                }
                ws.onerror = function () {
                    console.log("连接出错");
                }

                close.onclick = function () {
                    ws.onclose();
                    ws.send(input.value + 'close' + "了连接");
                    input.removeAttribute("readOnly");
                    conn.disabled = false;
                    close.disabled = true;
                }
            }
        }
    </script>
</body>

</html>

 server.js

var ws = require("nodejs-websocket");
console.log("开始建立连接...");
var str1 = null, str2 = null, clientReady = false, serverReady = false;
var a = [];
var server = ws.createServer(function (conn) {
    conn.on('text', function (str) {
          a.push(str);
        if (!clientReady) {
            if (a[0] === str) {
                str1 = conn;
                clientReady = true;
                str1.sendText("欢迎你" + str);
                
            }
        } else if (!serverReady) {
            if (str.indexOf('close') >= 0) {    
                     a.splice(2,1);
                     clientReady = false;
                     str1=null;   
                     return;
                }
            if (a[1] === str) {
                str2 = conn;
                serverReady = true;
                str2.sendText("欢迎你" + str);
                str1.sendText(str + "在线啦,你们可以聊天啦");
                return;
            } 
        } else if (clientReady && serverReady) {
                str2.sendText(str);
                str1.sendText(str);
                if (str.indexOf('close') >= 0) {
                    a.splice(2, a.length);
                    var len = a.length;
                    for (var i = 0; i < len; i++) {
                        // 定位该元素位置
                        if (str.indexOf(a[i])>=0) {     
                           a.splice(i,1);
                           if(i==0){
                               str1=str2;
                           }
                           serverReady = false; 
                           str2=null;
                           return;
                        }
                      
                    } 
                }
            }  
            
            
    })

    conn.on("close", function (code, reason) {
        console.log("关闭连接");
        clientReady = false;
        serverReady = false;
    })
    conn.on("error", function (code, reason) {
        console.log("异常关闭");
    });
}).listen(8082);
console.log("websocket连接完毕")

 实现双人聊天,client.html开启两个窗口就行!

 详细代码在github上:

 https://github.com/sulishibaobei/websocket-
 

 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 打造自己的 nodejs 静态文件服务器(帖子内容,
    用NodeJS打造你的静态文件服务器在《The Node Beginner Book》的中文版(http://nodebeginner.org/index-zh-cn.html)发布之后,获得国内的好评。也有同学觉得这本书略薄,没有包含进阶式的例子。@otakustay同学说:“确实,我的想法是在这之上补一个简单的MV
    02-10
  • NodeJS无所不能:细数10个令人惊讶的NodeJS开源
    在几年的时间里,NodeJS逐渐发展成一个成熟的开发平台,吸引了许多开发者。有许多大型高流量网站都采用NodeJS进行开发,像PayPal,此外,开发人员还可以使用它来开发一些快速移动Web框架。  除了Web应用外,NodeJS也被应用在许多方面,本文盘点了NodeJS在其
    02-10
  • Linux环境下的Nodejs linux安装基本环境
    最近在学习Node.js,在window下总是觉得不那么爽快。最简单而且环保的方法是在虚拟机中安装一个Linux。 { 1.Linux:家中的Linux为Centos。 2.VirtuallyBox: 开启2块网卡。第一个选Host-Only目的是为了让虚拟机通上网。第二块选Bridge Adapter,这是为了
    02-09
  • nodejs package.json说明
    {"name": "test", //项目名称(必须),由小写英文字母、数字和下划线,不能含空格"version": "1.0.0", //项目版本(必须)"description": "This is for study gulp project !", //项目描述(必须)"homepage": "", //项目主页url " key
    02-09
  • 017 nodejs取参四种方法req.body,req.params,re
    摘要: nodejs取参四种方法req.body,req.params,req.param,req.body 获取请求很中的参数是每个web后台处理的必经之路,nodejs提供了四种方法来实现。获取请求很中的参数是每个web后台处理的必经之路,nodejs的 express框架 提供了四种方法来实现。req.bodyre
    02-09
  • Docker windows下安装并搭建Nodejs的webapp
    Docker windows下安装并搭建Nodejs的webapp
    一、关于Docker什么是Docker?Docker 采用go语言编写,是一个开源的应用容器引擎。让开发者可以快速打包他们的应用以及依赖包到一个封装的可移植的容器Image中,然后发布到任何流行的机器( Linux ,windows,Mac等)上,也可以实现虚拟化。容器是使用完全
    02-09
  • Nodejs+Express+Mysql实现简单用户管理增删改查
    Nodejs+Express+Mysql实现简单用户管理增删改查
     源码地址  https://github.com/king-y/NodeJs/tree/master/user目录结构  mysql.jsvar mysql = require('mysql');var pool = mysql.createPool({host : '127.0.0.1',user : 'root',password : '',database : 's79'});exports.que
    02-09
  • nodejs查看本机hosts文件域名对应ip
    const dns = require('dns')dns.lookup('domainName', function(err, result) {console.log(result)}) related:https://***.com/questions/36689536/how-to-resolve-hostname-to-an-ip-address-in-node-js
    02-09
  • nodejs process.memoryUsage() rss等参数啥含义
    nodejs process.memoryUsage() rss等参数啥含义
    1 前言使用process.memoryUsage() ,然后可以得到一个对象如下:{ rss: 4935680,heapTotal: 1826816,heapUsed: 650472,external: 49879}  然而不知道rss是什么缩写,不知道其含义,网上找了一圈,多数都没说到点上,我这边就补充一下,也作为记录使用。2 
    02-09
  • nodejs工程拷贝后运行报module找不到问题
    工程文件夹通过复制黏贴到另外一个地方,运行后报错 “can`t find module 某某某”,查看原因:输入node 进入控制台,输入console.log(module.paths)查看当前nodejs查找module的路径,如果没有工程里的node_modules,通过module.paths.push加入,检查是否有效
    02-09
点击排行