前言

详解 HTTP系列之一讲到HTTP/2.0 突破了传统的“请求-问答模式”这一局限,实现了服务器主动向客户端传送数据。而本章将通过一种在单个TCP连接上进行全双工通信的协议--websocket协议,实现一个简单的聊天室(本文转载自xing.org1^大佬的博客,详情请点击此处跳转




核心要点

聊天室的核心要点是由服务器向每个正在连接的用户发送消息,也就是上面讲到的改变。如果不是这样,只能是客户端以一个很短的时间间隔向服务端请求数据。

要做到广播,就需要server.connections,这个数组记录了所有连接到websocket服务器的用户(也就是进入聊天室的人),通过遍历这个数组,然后给数组中每个连接进来的用户对象发送消息即可。

实现这一功能的代码如下:

const ws = require('nodejs-websocket');
const server = ws.createServer((connect)=>{
/*
......
*/ // 对连接到服务端的每个对象发送数据
function broadcast(jsonStr){
server.connections.forEach((element)=>{ //切记,send参数必须是字符串类型,所以这里将对象字符串化
element.send(JSON.stringify(jsonStr));
});
}
})

 

 

聊天室实现代码

环境:

  • nodejs
  • npm install nodejs-websocket

 

客户端 test.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>小石头的群聊</title>
</head> <body>
<div class="container">
<input type="text" placeholder="请输入要发送的内容" id="ipt">
<button id="btn">发送</button>
<button id="closeBtn">退出群聊</button>
<p>
群聊内容如下:
</p>
<div id="rst" style="width: 800px;height: 500px;background-color: greenyellow;"></div>
</div>
<script>
// 聊天室功能
const ws = new WebSocket('ws://localhost:8081'),
ipt = document.getElementById('ipt'),
btn = document.getElementById('btn'),
closeBtn = document.getElementById('closeBtn'),
content = document.getElementById('rst'); // 初次进入聊天室,给个提醒
ws.addEventListener('open', (e) => {
console.log('加入聊天室成功', e);
content.appendChild(creatEle('您已成功加入小石头的群聊~')); //
// 聊天区滚动到底
goBottom();
}); // 接收ws服务器发送的消息,并展示到div#rst当中
ws.addEventListener('message', (e) => {
console.log(e.data);
content.appendChild(creatEle(e.data));
goBottom();
}); // 一个带滚动条的DIV元素,怎么让它的滚动条位置默认保持在最底部?
function goBottom() {
content.scrollTop = content.scrollHeight;
} // btn被点击时发送请求
btn.onclick = function () {
btnClickEvent();
}
ipt.addEventListener('keydown', (e) => {
if (e.keyCode === 13) {
btnClickEvent();
}
}); // close-btn被点击时退出群聊
closeBtn.onclick = function () {
ws.close();
} // 创建一个p标签,存储对应内容,以追加到内容展示区域
function creatEle(str) {
console.log(str.indexOf('{'));
const TYPE_LEAVE = 0; //leave,离开
const TYPE_ENTRY = 1; //entry,进入
const TYPE_SPEAK = 2; //speak,发言
const eleP = document.createElement('p'); if (str.indexOf('{') == 0) {
let parseStr = JSON.parse(str);
eleP.innerHTML = `<span class="timer">${parseStr.time}</span><br/><span class="msg">${parseStr.msg}</span>`;
switch (parseStr.type) {
case TYPE_LEAVE:
eleP.className = 'leave';
break;
case TYPE_ENTRY:
eleP.className = 'entry';
break;
case TYPE_SPEAK:
eleP.className = 'speek';
break;
default:
eleP.className = 'default';
break;
}
} else {
eleP.innerText = str;
}
return eleP;
}
// 添加回车发送消息事件
function btnClickEvent() {
if (ipt.value.length <= 0) {
alert('不能发送空消息');
return;
}
ws.send(ipt.value);
ipt.value = '';
}
</script>
</body>
</html>

 

服务端 server.js:

/*
* @Author: @Guojufeng
* @Date: 2019-06-02 19:42:06
* @Last Modified by: @Guojufeng
* @Last Modified time: 2019-06-02 21:39:56
* 优化 - 加入消息类型和当前时间的响应
*/
const ws = require('nodejs-websocket');
const POST = 8081; let count = 0;//记录加入人数 const TYPE_LEAVE = 0;//leave,离开
const TYPE_ENTRY = 1;//entry,进入
const TYPE_SPEAK = 2;//speak,发言 const server = ws.createServer((connect)=>{
count++;// 有人加入,计数加一
connect.userName = `用户${count}`;//connet是一个对象,新增一个属性用以标记该用户的名字(标识) // 1、通知所有人,connect用户加入群聊
broadcast({
type: TYPE_ENTRY,
msg: `${connect.userName}加入群聊。`
}); // 2、通知所有人,connect用户发言
connect.on('text',(rst)=>{
broadcast({
type: TYPE_SPEAK,
msg: `${connect.userName}: ${rst}`
});
}); // 3、通知所有人,connect用户退出群聊
connect.on('close',(code,reason)=>{//个人认为利用code和reason这里,还可以模拟微信群聊中,用户被群主踢出群的情况
broadcast({
type: TYPE_LEAVE,
msg: `${connect.userName}退出了群聊。`
});
count--;// 有人退出,计数减一
}); // error事件
connect.on('error',()=>{
console.log('发生异常');
})
}); // 广播功能代码
function broadcast(cont){
// 利用connections是存放所有加入群聊用户的数组,来给所有人广播内容
let sendCont = {
type: cont.type,
msg: cont.msg,
time: new Date().toLocaleTimeString()
};
server.connections.forEach((element)=>{
element.send(JSON.stringify(sendCont));//切记,send参数必须是字符串类型,所以这里将对象字符串化
});
} server.listen(POST,()=>{
console.log(`${POST}服务器启动成功。`)
});

启动服务:

  1. nodejs执行server.js文件,并成功监听到对应端口
  2. 浏览器打开index.html(可开启多个页面模拟多个用户),进行测试




结语


时间:2020/08/16 11:10

坐标:广东深圳


小案例-WebSocket实现简易聊天室的更多相关文章

  1. 基于Node.js + WebSocket 的简易聊天室

    代码地址如下:http://www.demodashi.com/demo/13282.html Node.js聊天室运行说明 Node.js的本质就是运行在服务端的JavaScript.Node.js ...

  2. node.js+websocket实现简易聊天室

    (文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) websocket提供了一种全双工客户端服务器的异步通信方法,这种通信方法使用ws或者wss协议,可 ...

  3. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  4. node+websocket创建简易聊天室

    关于websocket的介绍太多,在这就不一一介绍了,本文主要实现通过websocket创建一个简易聊天室,就是90年代那种聊天室 服务端 1.安装ws模块,uuid模块,ws是websocket模块 ...

  5. 使用Html5下WebSocket搭建简易聊天室

    一.Html5WebSocket介绍 WebSocket protocol 是HTML5一种新的协议(protocol).它是实现了浏览器与服务器全双工通信(full-duplex). 现在,很多网站 ...

  6. WebSocket实现简易聊天室

    前台页面: <html> <head> <meta http-equiv="Content-Type" content="text/html ...

  7. 基于WebSocket的简易聊天室

    用的是Flash + WebSocket 哦~ Flask 之 WebSocket 一.项目结构: 二.导入模块 pip3 install gevent-websocket 三.先来看一个一对一聊天的 ...

  8. Java WebSocket实现简易聊天室

    一.Socket简介 Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求.Socket的英文原义是“孔”或“插座”,作为UNI ...

  9. Servlet WebSocket的简易聊天室

    添加依赖 <!-- websocket --> <dependency> <groupId>javax.websocket</groupId> < ...

随机推荐

  1. Python List max()方法

    描述 max() 方法返回列表元素中的最大值.高佣联盟 www.cgewang.com 语法 max()方法语法: max(list) 参数 list -- 要返回最大值的列表. 返回值 返回列表元素 ...

  2. Codeforces Round #649 (Div. 2) E. X-OR 交互 二进制 随机 期望

    LINK:X-OR 本来是应该昨天晚上发的 可是昨天晚上 做这道题 写了一个分治做法 一直wa 然后查错 查不出来 心态崩了 想写对拍 发现交互库自己写不出来. 一系列sb操作 == 我都醉了. 今天 ...

  3. Java 将数据写入全路径下的指定文件

    package com.freud.algorithm.other; import java.io.File; import java.io.FileOutputStream; public clas ...

  4. springboot2.1.x版本报错总结

    我使用的是springboot  2.1.7.RELEASE  springcloud  Greenwich.SR2 boot和cloud对应的版本号不能搞混,对应版本请参考https://sprin ...

  5. Vue通过Blob对象实现导出Excel功能

    不同的项目有不同的导出需求,有些只导出当前所显示结果页面的表格进入excel,这个时候就有很多插件,比如vue-json-excel或者是Blob.js+Export2Excel.js来实现导出Exc ...

  6. DeepVO: Towards End-to-End Visual Odometry with Deep Recurrent Convolutional Neural Networks

    1.Introduction DL解决VO问题:End-to-End VO with RCNN 2.Network structure a.CNN based Feature Extraction 论 ...

  7. linux查询操作系统信息,CPU物理个数,CPU核心数,逻辑CPU数,内存信息查询,硬盘信息查询

    目录 一.前言 二.关于服务器基本配置 2.1 操作系统基本配置查询 2.2 CPU基本配置查询 2.3 内存基本配置查询 2.4 硬盘基本配置查询 一.前言 ​ 当我们接手了一台或者几台服务器的时候 ...

  8. Windows-快速预览文件-QuickLook

    开源.免费的文件快速预览工具, 支持图片.文档.音视频.代码文本.压缩包等多种格式. 获得 Mac OS 空格键快速预览文件相同的体验 效果图 文件夹 音视频 浏览 压缩包,文本 支持的格式: 图片: ...

  9. 2、适配器 adapter 模式 加个"适配器" 以便于复用 结构型设计模式

    1.什么是适配器模式? 适配器如同一个常见的变压器,也如同电脑的变压器和插线板之间的电源连接线,他们虽然都是3相的,但是电脑后面的插孔却不能直接插到插线板上. 如果想让额定工作电压是直流12伏特的笔记 ...

  10. 使用Luhn算法实现信用卡号验证

    问题描述: 2:信用卡号的验证 [信用卡号的验证] 当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么 担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过 Luhn 算法 ...