当前位置: 首页 > news >正文

基于websocket与node搭建简易聊天室

一、前言

上一篇文章介绍了websocket的详细用法与工具类的封装,本篇就基于websocket搭建一个简易实时的聊天室。

在本篇开始之前也可以去回顾一下websocket详细用法:WebSocket详解与封装工具类

在这里插入图片描述

二、基于node搭建后台websocket服务

首先确认本机电脑中是否安装node,可以通过cmd打开命令窗口运行node -v查看node版本;

  1. 建议创建一个空项目:
npm init
  1. 一路回车就行,然后就得到了一个package.json的配置文件;安装ws模块
npm i ws
  1. 新建app.js文件,源码如下:
const WebSocket = require('ws');
// 随机姓名
const names = ['赵', '钱', '孙', '李', '周', '吴', '郑', '王', '冯', '陈', '褚', '卫', '蒋', '沈', '韩', '杨', '朱', '秦', '尤', '许', '何','吕', '施', '张', '孔', '曹', '严', '华', '金', '魏', '陶', '姜', '戚', '谢', '邹', '喻', '柏', '水', '窦', '章', '云', '苏', '潘', '葛','奚', '范', '彭', '郎', '鲁', '韦', '昌', '马', '苗', '凤', '花', '方', '俞', '任', '袁', '柳', '酆', '鲍', '史', '唐', '费', '廉', '岑','薛', '雷', '贺', '倪', '汤', '滕', '殷', '罗', '毕', '郝', '邬', '安', '常', '乐', '于', '时', '傅', '皮', '卞', '齐', '康', '伍', '余','元', '卜', '顾', '孟', '平', '黄', '和', '穆', '萧', '尹'
];
// 获取随便昵称
const getRandom = (min, max) => {return Math.floor(Math.random() * (min - max) + max)
};
// 创建 WebSocket 服务器实例
const wss = new WebSocket.Server({port: 8080
});
// 监听连接事件
wss.on('connection', function(socket) {console.log('新连接');const randomIndex = getRandom(0, names.length - 1);socket.nickname = names.splice(randomIndex, 1)[0];sendMessageToClient( '连接成功!进入聊天室!');// 监听接收消息事件socket.on('message', function(message) {sendMessageToClient(message);});// 监听接收消息事件socket.on('close', function() {// 广播消息给所有客户端wss.clients.forEach(function each(client) {if (client.readyState === WebSocket.OPEN) {client.send(JSON.stringify({nickname: socket.nickname,msg: '退出聊天室!',}));}});});// 监听接收消息事件socket.on('error', function() {// 广播消息给所有客户端wss.clients.forEach(function each(client) {if (client.readyState === WebSocket.OPEN) {client.send(JSON.stringify({nickname: socket.nickname,msg: '网络不佳,连接失败 !',}));}});});// 发送消息到客户端function sendMessageToClient(message) {let targetMsg = message instanceof Buffer ? message.toString() : message;// 广播消息给所有客户端wss.clients.forEach(function each(client) {if (client.readyState === WebSocket.OPEN) {client.send(JSON.stringify({nickname: socket.nickname,msg: targetMsg,}));}});}
});
  1. 最后启动node服务:node app.js;

三、前端构建聊天室

3.1 确定功能点

  1. 会话框中展示聊天内容;
  2. 输入框与发送按钮发送消息内容;
  3. 连接websocket,监听实时消息展示到界面中;

3.2 界面结构搭建

在这里插入图片描述

代码结构:

<div class="main_container"><!-- 消息框 --><div id="msgList"></div><!-- 发送消息 --><div class="controls"><input type="text" class="pushMsg" /><button id="btn">发送</button></div>
</div>

3.3 代码逻辑

  1. 引入之前封装的websocket工具类;

    <script src="./utils/websocket.js"></script>
    
  2. 实例化连接websocket;

    const newWebSocket = new WebSocketClient('ws:localhost:8080');
    newWebSocket.connect();
    
  3. 定义消息列表,监听返回消息信息,根据消息展示到界面中;

    // 消息列表
    const msgList = [];
    newWebSocket.addEventListener('message', handleMessage);
    // 处理返回数据
    function handleMessage(msg) {const msgData = JSON.parse(msg.data || '{}');console.log(msgData, "返回数据====");if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {msgList.push({name: msgData.nickname,msg: msgData.msg,});const str = msgList.reduce((cur, next) => {let curMsg = '';if (next.msg.includes('连接')) {curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;} else {curMsg = `<div class="msg_line"><div class="avatar">${next.name}</div><div class="msg_text">${next.msg}</div></div>`;}return cur += curMsg;}, '');$('#msgList').html(str);// 获取设置了滚动属性的div标签const div = document.getElementById('msgList');// 设置滚动的顶点坐标为滚动的总高度div.scrollTop = div.scrollHeight;}
    }newWebSocket.addEventListener('message', handleMessage);
    // 处理返回数据
    function handleMessage(msg) {const msgData = JSON.parse(msg.data || '{}');console.log(msgData, "返回数据====");if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {msgList.push({name: msgData.nickname,msg: msgData.msg,});const str = msgList.reduce((cur, next) => {let curMsg = '';if (next.msg.includes('连接')) {curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;} else {curMsg = `<div class="msg_line"><div class="avatar">${next.name}</div><div class="msg_text">${next.msg}</div></div>`;}return cur += curMsg;}, '');$('#msgList').html(str);// 获取设置了滚动属性的div标签const div = document.getElementById('msgList');// 设置滚动的顶点坐标为滚动的总高度div.scrollTop = div.scrollHeight;}
    }
    
  4. 监听输入框回车事件,与发送按钮点击事件,发送消息;

    // 监听发送按钮
    $('#btn').on('click', sendMessage);// 输入框回车事件
    $('.pushMsg').keydown(function(event) {if (event.key === 'Enter') {sendMessage();}
    });
    // 发送消息
    function sendMessage() {const msg = $('.pushMsg').val();if (msg) {newWebSocket.send(`${msg}`);$('.pushMsg').val('');}
    }
    

四、涉及小知识点

  1. 取消滚动条的展示,发送消息后默认展示最下方数据;

    #msgList::-webkit-scrollbar {width: 0;
    }
    
    // 获取设置了滚动属性的div标签
    const div = document.getElementById('msgList');
    // 设置滚动的顶点坐标为滚动的总高度
    div.scrollTop = div.scrollHeight;
    
  2. 输入框监听keydown事件,当key为Enter时发送消息(也可设置其他按键)

    // 输入框回车事件
    $('.pushMsg').keydown(function(event) {if (event.key === 'Enter') {sendMessage();}
    });
    
  3. 取消input的光标进入的表框效果

    outline: none;
    
  4. 鼠标小手的出现

    cursor: pointer;
    

五、聊天室完整前端源码

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>聊天通信</title><script src="./utils/jquery.min.js"></script><script src="./utils/websocket.js"></script><style>.main_container {width: 500px;margin: auto;}#msgList {width: 500px;height: 400px;overflow: auto;border: 2px solid #8491fe;border-radius: 10px;padding: 6px;background-color: #ebffff;box-sizing: border-box;}#msgList::-webkit-scrollbar {width: 0;}.msg_line {margin: 10px 0;display: flex;flex-wrap: wrap;}.avatar {width: 30px;height: 30px;border-radius: 50%;background-color: #77ffff;text-align: center;line-height: 30px;color: #333;font-size: 12px;margin-right: 6px;}.msg_text {display: inline-block;padding: 4px 12px;border-radius: 6px;background-color: #f0f1dd;font-size: 14px;}.center_msg {text-align: center;color: #f19597;}.controls {width: 100%;display: flex;justify-content: space-between;margin-top: 10px;}input {flex: 1;outline: none;height: 34px;line-height: 34px;border: 1px solid #d8d8d8;border-radius: 4px;padding: 0 4px;color: #333;margin-right: 12px;}#btn {width: 80px;height: 34px;cursor: pointer;}</style></head><body><div class="main_container"><!-- 消息框 --><div id="msgList"></div><!-- 发送消息 --><div class="controls"><input type="text" class="pushMsg" /><button id="btn">发送</button></div></div><script src="./utils/websocket.js"></script><script>// 消息列表const msgList = [];// 初始化websocketconst newWebSocket = new WebSocketClient('ws:localhost:8080');newWebSocket.connect();window.NewWebSocket = newWebSocket;newWebSocket.addEventListener('message', handleMessage);// 处理返回数据function handleMessage(msg) {const msgData = JSON.parse(msg.data || '{}');console.log(msgData, "返回数据====");if (msgData && typeof msgData.msg === 'string' && !msgData.msg.includes('ping')) {msgList.push({name: msgData.nickname,msg: msgData.msg,});const str = msgList.reduce((cur, next) => {let curMsg = '';if (next.msg.includes('连接')) {curMsg = `<div class="center_msg">玩家:${next.name}_${next.msg}</div>`;} else {curMsg = `<div class="msg_line"><div class="avatar">${next.name}</div><div class="msg_text">${next.msg}</div></div>`;}return cur += curMsg;}, '');$('#msgList').html(str);// 获取设置了滚动属性的div标签const div = document.getElementById('msgList');// 设置滚动的顶点坐标为滚动的总高度div.scrollTop = div.scrollHeight;}}// 监听发送按钮$('#btn').on('click', sendMessage);// 输入框回车事件$('.pushMsg').keydown(function(event) {if (event.key === 'Enter') {sendMessage();}});// 发送消息function sendMessage() {const msg = $('.pushMsg').val();if (msg) {newWebSocket.send(`${msg}`);$('.pushMsg').val('');}}</script></body>
</html>

相关文章:

基于websocket与node搭建简易聊天室

一、前言 上一篇文章介绍了websocket的详细用法与工具类的封装&#xff0c;本篇就基于websocket搭建一个简易实时的聊天室。 在本篇开始之前也可以去回顾一下websocket详细用法&#xff1a;WebSocket详解与封装工具类 二、基于node搭建后台websocket服务 首先确认本机电脑中…...

DevOps全面综述:从概念到实践

一、背景与概述 1.1 DevOps的起源与发展 DevOps&#xff08;Development and Operations的缩写&#xff09;是软件工程领域中的一种文化和实践方法&#xff0c;旨在促进开发团队与运维团队之间的协作&#xff0c;从而实现更高效、更可靠的软件交付。DevOps起源于敏捷软件开发方…...

[C++]vector的模拟实现

下面是简单的实现vector的功能&#xff0c;没有涉及使用内存池等复杂算法来提高效率。 一、vector的概述 &#xff08;一&#xff09;、抽象数据类型定义 容器&#xff1a;向量&#xff08;vector&#xff09;vector是表示大小可以变化的数组的序列容器。像数组一样&#xf…...

【云原生】Kubernetes----POD控制器

目录 引言 一、Pod控制器概述 二、Pod控制器的种类 &#xff08;一&#xff09;ReplicaSet &#xff08;二&#xff09;Deployment &#xff08;三&#xff09;StatefulSet &#xff08;四&#xff09;DaemonSet &#xff08;五&#xff09;Job 三、使用POD控制器 &a…...

Java环境配置(超详细)

Java环境配置&#xff08;超详细&#xff09; 引言1、安装 JDK1.1、下载安装JDK1.2、配置环境变量&#xff1a;JAVA_HOME1.3、将JAVA_HOME添加到Path中 2、安装 Maven2.1、下载安装Maven2.2、配置maven的环境变量: M2_HOME2.3、将Maven变量添加到Path中 引言 Java开发环境的配…...

【操作系统】(详细理解进程的状态)执行状态、就绪状态、阻塞状态、挂起状态

下面是进程的几种状态的概念&#xff1a; 执行状态&#xff1a;当一个进程已获得必要资源&#xff0c;并占有CPU进行执行。 就绪状体&#xff1a;进程已分配到除CPU外的所有必要资源&#xff0c;只要获取CPU允许就可立即执行。 阻塞状态&#xff1a;正在执行的进程&#xff0c;…...

C++ -- string常用接口的底层实现

一.string介绍 1. string是表示字符串的字符串类&#xff0c;对C语言的字符串指针进行了包装。 2. 该类的接口与常规容器的接口基本相同&#xff0c;有增删查改等&#xff0c;再添加了一些专门用来操作string的常规操作。 二.成员变量 创建string类的时候要在自己的命名空间…...

怎么做好企业短信服务呢?(文字短信XML接口示例)

企业短信服务已经成为各行各业都信赖的行业推广方式之一&#xff0c;并且短信行业也与时俱进的发展着&#xff0c;随之而来的就是市场上短信平台的数量也随之增多。那么怎么在鱼龙混杂的短信行业中选择适合自己的企业短信服务平台呢&#xff1f;企业短信服务平台又适用于哪些应…...

鸿蒙小案例-音乐播放器

之前参加鸿蒙比赛的音乐播放器 效果展示 HF音乐效果展示 功能列 有一些功能没写上去&#xff0c;自行发掘 说明&#xff1a; 1.API:网易云接口&#xff0c;QQ个人接口&#xff0c; 需要请看gitee 2.本地关系型数据由bug,提的工单已确认&#xff0c;建议使用API11,12,9的不稳…...

语言模型测试系列【9】

语言模型 文心一言讯飞星火通义千问2.5豆包360智脑百小应腾讯元宝KimiC知道 好长时间没有做语言模型的测试了&#xff0c;一方面是没有好的素材&#xff0c;各模型都在升级优化&#xff0c;而且频率很高&#xff1b;另一方面近期在阅读和学习其他的知识&#xff0c;所以更的也…...

优思学院|质量工程师工资不高怎么办?

你是否曾经好奇&#xff0c;为什么在职场中&#xff0c;质量工程师的工资普遍不高&#xff1f;这一现象背后的原因&#xff0c;实际上与他们的职业门槛和专业知识密切相关。早期&#xff0c;国内的质量工程师入行门槛较低&#xff0c;许多人即使没有任何专业知识也可以进入这一…...

【面向就业的Liux基础】从入门到熟练,探索Linux的秘密(一)

主要帮助大家面向工作过程中Linux系统常用的命令联系&#xff0c;采用极致的实用主义&#xff0c;帮助大家节省时间。 文章目录 前言 一、linux系统 二、linux系统基本命令 1.Linux系统的目录结构 2. 常用命令介绍 3.命令演示 4.作业练习 总结 前言 主要帮助大家面向工作过程中…...

高效数据处理的前沿:【C++】、【Redis】、【人工智能】与【大数据】的深度整合

目录 1.为什么选择 C 和 Redis&#xff1f; 2.人工智能与大数据的背景 1.大数据的挑战 2.人工智能的需求 3.C 与 Redis 的完美结合 1.安装 Redis 和 Redis C 客户端 2.连接 Redis 并进行数据操作 高级数据操作 列表操作 哈希操作 4.与大数据和人工智能结合 5.实际应…...

Vitis HLS 学习笔记--控制驱动与数据驱动混合编程

目录 1. 简介 2. 示例分析 2.1 代码分析 2.2 控制驱动TLP的关键特征 2.3 数据驱动TLP的关键特征 3. 总结 1. 简介 在 HLS 硬件加速领域&#xff0c;Vitis HLS 提供了强大的抽象并行编程模型。这些模型包括控制驱动和数据驱动的任务级并行性&#xff08;TLP&#xff09;&…...

VUE3 学习笔记(12):对比Vuex与Pinia状态管理的基本理解

在组件传值中&#xff0c;当嵌套关系越来越复杂的时候必然会将混乱&#xff0c;是否可以把一些值存在一个公共位置&#xff0c;无须传值直接调用呢&#xff1f;VUEX应运而生&#xff0c;但是从VUE3开始对VUEX的支持就不那么高了&#xff0c;官方推荐使用Pinia。 Vuex配置 ST1:…...

区间预测 | Matlab实现QRCNN-BiGRU-Attention分位数回归卷积双向门控循环单元注意力机制时序区间预测

区间预测 | Matlab实现QRCNN-BiGRU-Attention分位数回归卷积双向门控循环单元注意力机制时序区间预测 目录 区间预测 | Matlab实现QRCNN-BiGRU-Attention分位数回归卷积双向门控循环单元注意力机制时序区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实…...

TypeScript算法每日一题:赎金信(383)

作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者✍/CSDN百万访问博主/B站千粉前端up主 题库&#xff1a;力扣 题目序号&#xff1a;383&#xff08;简单&#xff09; 题目&#xff1a;赎金信 给你两个字符串ransomNote 和 magazine&#xff0c;判断ran…...

springboot 作为客户端接收服务端的 tcp 长连接数据,并实现自定义结束符,解决 粘包 半包 问题

博主最近的项目对接了部分硬件设备&#xff0c;其中有的设备只支持tcp长连接方式传输数据&#xff0c;博主项目系统平台作为客户端发起tcp请求到设备&#xff0c;设备接收到请求后作为服务端保持连接并持续发送数据到系统平台。 1.依赖引入 连接使用了netty&#xff0c;如果项…...

kuka编程怎么加中文:解锁KUKA机器人编程中的中文支持

kuka编程怎么加中文&#xff1a;解锁KUKA机器人编程中的中文支持 在工业自动化领域&#xff0c;KUKA机器人以其卓越的性能和广泛的应用而备受赞誉。然而&#xff0c;对于许多中国用户来说&#xff0c;如何在KUKA编程中加入中文支持却成为了一个挑战。本文将从四个方面、五个方…...

hadoop集群中zookeeper的搭建与原理解释

搭建zookeeper 将zookeeper的apache-zookeeper-3.5.7-bin.tar.gz解压到/export/servers下 tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /export/servers为了方便后期使用解压后的文件夹改名为zookeeper-3.5.7 mv apache-zookeeper-3.5.7-bin zookeeper-3.5.7先进入zoo_…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...