Node.js实现WebSocket教程
Node.js实现WebSocket教程
1. WebSocket简介
WebSocket是一种在单个TCP连接上提供全双工通信的协议,允许服务器和客户端之间进行实时、双向通信。本教程将详细讲解如何在Node.js中实现WebSocket。
2. 技术选型
我们将使用ws库来实现WebSocket服务器,并结合express创建Web应用。
2.1 安装依赖
# 创建项目目录
mkdir nodejs-websocket-demo
cd nodejs-websocket-demo# 初始化项目
npm init -y# 安装依赖
npm install express ws uuid
依赖说明:
express: Web应用框架ws: WebSocket服务器实现uuid: 生成唯一标识符
3. 项目结构
nodejs-websocket-demo/
│
├── public/
│ ├── index.html
│ └── client.js
├── server.js
└── package.json
4. 详细实现
4.1 WebSocket服务器 (server.js)
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const { v4: uuidv4 } = require('uuid');const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });// 存储客户端连接
const clients = new Map();// 静态文件服务
app.use(express.static('public'));// WebSocket连接处理
wss.on('connection', (ws) => {// 为每个客户端分配唯一IDconst clientId = uuidv4();// 存储客户端连接clients.set(clientId, ws);// 发送客户端IDws.send(JSON.stringify({type: 'connection',clientId: clientId}));// 广播新用户连接broadcast({type: 'userJoined',clientId: clientId,message: `用户 ${clientId} 已加入聊天`}, clientId);// 消息处理ws.on('message', (message) => {try {const parsedMessage = JSON.parse(message);switch(parsedMessage.type) {case 'chat':handleChatMessage(clientId, parsedMessage);break;case 'typing':handleTypingNotification(clientId, parsedMessage);break;default:console.log('未知消息类型:', parsedMessage.type);}} catch (error) {console.error('消息解析错误:', error);}});// 连接关闭处理ws.on('close', () => {// 移除客户端clients.delete(clientId);// 广播用户离开broadcast({type: 'userLeft',clientId: clientId,message: `用户 ${clientId} 已离开聊天`}, clientId);});
});// 聊天消息处理
function handleChatMessage(senderId, message) {broadcast({type: 'chat',clientId: senderId,message: message.message}, senderId);
}// 输入状态通知
function handleTypingNotification(senderId, message) {broadcast({type: 'typing',clientId: senderId,isTyping: message.isTyping}, senderId);
}// 广播消息
function broadcast(message, excludeClientId = null) {clients.forEach((client, clientId) => {if (client.readyState === WebSocket.OPEN && clientId !== excludeClientId) {client.send(JSON.stringify(message));}});
}// 服务器启动
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {console.log(`WebSocket服务器运行在 ${PORT} 端口`);
});
4.2 客户端HTML (public/index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>WebSocket聊天室</title><style>body { font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }#chat-messages {height: 300px;overflow-y: scroll;border: 1px solid #ccc;padding: 10px;margin-bottom: 10px;}</style>
</head>
<body><div id="chat-messages"></div><input type="text" id="message-input" placeholder="输入消息"><button id="send-btn">发送</button><script src="client.js"></script>
</body>
</html>
4.3 客户端JavaScript (public/client.js)
const socket = new WebSocket('ws://localhost:3000');
let clientId = null;const chatMessages = document.getElementById('chat-messages');
const messageInput = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');// WebSocket事件处理
socket.addEventListener('open', (event) => {appendMessage('系统', '连接成功');
});socket.addEventListener('message', (event) => {const message = JSON.parse(event.data);switch(message.type) {case 'connection':clientId = message.clientId;appendMessage('系统', `您的ID是: ${clientId}`);break;case 'chat':appendMessage(message.clientId, message.message);break;case 'userJoined':case 'userLeft':appendMessage('系统', message.message);break;case 'typing':handleTypingNotification(message);break;}
});socket.addEventListener('close', (event) => {appendMessage('系统', '连接已关闭');
});// 发送消息
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {if (e.key === 'Enter') {sendMessage();}
});function sendMessage() {const message = messageInput.value.trim();if (message) {socket.send(JSON.stringify({type: 'chat',message: message}));appendMessage(clientId, message);messageInput.value = '';}
}// 消息追加到聊天窗口
function appendMessage(sender, text) {const messageEl = document.createElement('div');messageEl.innerHTML = `<strong>${sender}:</strong> ${text}`;chatMessages.appendChild(messageEl);chatMessages.scrollTop = chatMessages.scrollHeight;
}// 处理打字状态通知
function handleTypingNotification(message) {// 可以在这里实现打字状态提示
}
5. 运行项目
# 启动服务器
node server.js# 访问 http://localhost:3000
6. 功能特点
- 实时双向通信
- 唯一客户端标识
- 广播消息机制
- 连接/断开事件处理
- 聊天消息和系统通知
7. 性能与扩展建议
- 生产环境考虑使用Redis等外部存储管理WebSocket连接
- 增加身份验证机制
- 实现消息持久化
- 使用负载均衡
8. 安全注意事项
- 使用WSS(WebSocket Secure)
- 实现连接速率限制
- 验证和过滤消息内容
- 防止跨站WebSocket劫持
相关文章:
Node.js实现WebSocket教程
Node.js实现WebSocket教程 1. WebSocket简介 WebSocket是一种在单个TCP连接上提供全双工通信的协议,允许服务器和客户端之间进行实时、双向通信。本教程将详细讲解如何在Node.js中实现WebSocket。 2. 技术选型 我们将使用ws库来实现WebSocket服务器,…...
Docker Compose实战一( 轻松部署 Nginx)
通过过前面的文章(Docker Compose基础语法)你已经掌握基本语法和常用指令认识到Docker Compose作为一款强大工具的重要性,它极大地简化了多容器Docker应用程序的部署与管理流程。本文将详细介绍如何使用 Docker Compose 部署 Nginx࿰…...
hive分区分桶、数据倾斜总结
一、hive的基本概念 hive是一个构建在hadoop上的数据仓库工具,可以将结构化的数据文件映射为一张数据库表并提供数据查询功能 二、hive的特点 (1)数据是存储在hdfs上 (2)底层是将sql转换为MapReduce任务进行计算 …...
unity打包到安卓帧率降低
这个问题遇到过很多次了我的做法就是直接设置Application.targetFrameRate60 参考...
【Python3】装饰器 自动更新缓存
自动更新缓存的需求场景 在某些应用中,我们可能需要定期从外部数据源(如 Redis 或者远程接口)拉取数据,并将其缓存在内存中。当有其他代码需要访问这些数据时,可以立刻从内存获取最新数据,而无需每次都进行…...
通过EPEL 仓库,在 CentOS 7 上安装 OpenResty
通过EPEL 仓库,在 CentOS 7 上安装 OpenResty 通过EPEL 仓库,在 CentOS 7 上安装 OpenResty步骤 1: 安装 EPEL 仓库步骤 2: 安装 OpenResty步骤 3: 启动 OpenResty步骤 4: 设置开机自启步骤 5: 验证安装说明 通过EPEL 仓库,在 CentOS 7 上安装…...
[RabbitMQ] RabbitMQ常见应用问题
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
每日速记10道java面试题13-MySQL篇
其他资料 每日速记10道java面试题01-CSDN博客 每日速记10道java面试题02-CSDN博客 每日速记10道java面试题03-CSDN博客 每日速记10道java面试题04-CSDN博客 每日速记10道java面试题05-CSDN博客 每日速记10道java面试题06-CSDN博客 每日速记10道java面试题07-CSDN博客 每…...
乐鑫科技嵌入式面试题及参考答案(3万字长文)
嵌入式开发为什么用 C 语言,而不用 C++ 语言? 在嵌入式开发中,C 语言被广泛使用而 C++ 相对少用有以下一些原因。 首先,C 语言具有更高的效率。嵌入式系统通常资源受限,包括处理器速度、内存容量等。C 语言的代码生成效率高,能够生成紧凑的机器码,占用较少的内存空间和处…...
Leetcode 每日一题 56.合并区间
目录 问题描述 示例 示例 1 示例 2 问题分析 算法设计 步骤 1:排序 步骤 2:合并区间 步骤 3:返回结果 过题图片 代码实现 复杂度分析 题目链接 结语 问题描述 给定一个区间数组 intervals,其中每个区间由两个整数 s…...
【Vue】v-model、ref获取DOM
目录 v-moel v-model的原理 v-model用在组件标签上 方式 defineModel()简写 ref属性 获取原生DOM 获取组件实例 nextTick() v-moel v-model:双向数据绑定指令 数据变了,视图跟着变(数据驱动视图)视图变了,数…...
Python 类的设计(以植物大战僵尸为例)
关于类的设计——以植物大战僵尸为例 一、设计类需满足的三要素1. 类名2. 属性和方法 二、以植物大战僵尸的为例的类的设计1. 尝试分类2. 创建对象调用类的属性和方法*【代码二】*3. 僵尸的继承 三、代码实现 一、设计类需满足的三要素 1. 类名 类名:某类事物的名…...
python中权重剪枝,低秩分解,量化技术 代码
目录 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 低秩分解 scipy 量化技术 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 权重剪枝可以通过PyTorch的torch.nn.utils.prune模块实现。以下是一个简单的例子: import torch import torch.nn as nn impor…...
调用matlab用户自定义的function函数时,有多个输出变量只输出第一个变量
很多朋友在使用matlab时,会使用或自己编辑多个function函数,来满足自己对任务处理的要求,但是在调用function函数时,会出现这个问题:调用matlab用户自定义的function函数时,有多个输出变量只输出第一个变量…...
RabbitMQ七种工作模式之简单模式, 工作队列模式, 发布订阅模式, 路由模式, 通配符模式
文章目录 一. Simple(简单模式)公共代码:生产者:消费者: 二. Work Queue(工作队列模式)公共代码:生产者:消费者1, 消费者2(代码相同): 三. Publish/Subscribe(发布/订阅模式)公共代码:生产者:消费者: 四. Routing(路由模式)公共代码:消费者: 五. Topics(通配符模式)公共代码:生…...
Win10安装kafka并用C#调用
kafka安装 jdk、kafka版本如下,zookeeper使用kafka自带版本 安装包下载位置:https://download.csdn.net/download/henreash/90087368 (赚点csdn下载资源分) 安装jdk后,解压kafka压缩包,修改配置文件: kafka_2.13-3.9.0\config\…...
高级架构二 Git基础到高级
一 Git仓库的基本概念和流程 什么是版本库?版本库又名仓库,英文名repository,你可以简单的理解一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改,删除,Git都能跟踪,以便任何…...
深入解析二叉树算法
引言 二叉树(Binary Tree)作为数据结构中的一种重要形式,在计算机科学的诸多领域中得到了广泛应用。从文件系统到表达式解析,再到搜索和排序,二叉树都扮演着关键角色。本文将从二叉树的基础概念出发,详细探讨其各种算法及其应用,并提供相关代码示例,旨在为读者建立扎实…...
如何解决maven项目使用Ctrl + /添加注释时的顶格问题
一、问题描述 相信后端开发的程序员一定很熟悉IDEA编译器和Maven脚手架,使用IDEA新建一个Maven工程,通过SpringBoot快速构建Spring项目。在Spring项目pom.xml文件中想添加注释,快捷键Ctrl /,但是总是顶格书写。 想保证缩进统一…...
总结的一些MySql面试题
目录 一:基础篇 二:索引原理和SQL优化 三:事务原理 四:缓存策略 一:基础篇 1:定义:按照数据结构来组织、存储和管理数据的仓库;是一个长期存储在计算机内的、有组织的、可共享 的…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
STL 2迭代器
文章目录 1.迭代器2.输入迭代器3.输出迭代器1.插入迭代器 4.前向迭代器5.双向迭代器6.随机访问迭代器7.不同容器返回的迭代器类型1.输入 / 输出迭代器2.前向迭代器3.双向迭代器4.随机访问迭代器5.特殊迭代器适配器6.为什么 unordered_set 只提供前向迭代器? 1.迭代器…...
