Nodejs 第五十五章(socket.io)

news2024/11/23 7:46:24

传统的 HTTP 是一种单向请求-响应协议,客户端发送请求后,服务器才会响应并返回相应的数据。在传统的 HTTP 中,客户端需要主动发送请求才能获取服务器上的资源,而且每次请求都需要重新建立连接,这种方式在实时通信和持续获取资源的场景下效率较低。

image.png

Socket 提供了实时的双向通信能力,可以实时地传输数据。客户端和服务器之间的通信是即时的,数据的传输和响应几乎是实时完成的,不需要轮询或定时发送请求

image.png

安装依赖

在正常开发中,我们会使用成熟的第三方库,原生websocket,用的较少,一些简单的项目,或者一些普通的业务可以使用,不过大部分还是使用第三方库。

socket.io

Socket.IO 是一个基于事件驱动的实时通信框架,用于构建实时应用程序。它提供了双向、低延迟的通信能力,使得服务器和客户端可以实时地发送和接收数据。

Socket.IO 的主要特点包括:

  1. 实时性: Socket.IO 构建在 WebSocket 协议之上,使用了 WebSocket 连接来实现实时通信。WebSocket 是一种双向通信协议,相比传统的 HTTP 请求-响应模型,它可以实现更快速、低延迟的数据传输。
  2. 事件驱动: Socket.IO 使用事件驱动的编程模型。服务器和客户端可以通过触发事件来发送和接收数据。这种基于事件的通信模式使得开发者可以轻松地构建实时的应用程序,例如聊天应用、实时协作工具等。
  3. 跨平台支持: Socket.IO 可以在多个平台上使用,包括浏览器、服务器和移动设备等。它提供了对多种编程语言和框架的支持,如 JavaScript、Node.js、Python、Java 等,使得开发者可以在不同的环境中构建实时应用程序。
  4. 容错性: Socket.IO 具有容错能力,当 WebSocket 连接不可用时,它可以自动降级到其他传输机制,如 HTTP 长轮询。这意味着即使在不支持 WebSocket 的环境中,Socket.IO 仍然可以实现实时通信。
  5. 扩展性: Socket.IO 支持水平扩展,可以将应用程序扩展到多个服务器,并实现事件的广播和传递。这使得应用程序可以处理大规模的并发连接,并实现高可用性和高性能

nodejs 安装

npm install socket.io

浏览器使用esm

<script type="module">
import { io } from "https://cdn.socket.io/4.7.4/socket.io.esm.min.js";
 const socket = io('ws://localhost:3000'); //ws的地址
</script>

socket.io官网

聊天室

image.png

image.png

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        html,
        body,
        .room {
            height: 100%;
            width: 100%;
        }

        .room {
            display: flex;
        }

        .left {
            width: 300px;
            border-right: 0.5px solid #f5f5f5;
            background: #333;
        }

        .right {
            background: #1c1c1c;
            flex: 1;
            display: flex;
            flex-direction: column;
        }

        .header {
            background: #8d0eb0;
            color: white;
            padding: 10px;
            box-sizing: border-box;
            font-size: 20px;
        }

        .main {
            flex: 1;
            padding: 10px;
            box-sizing: border-box;
            font-size: 20px;
            overflow: auto;
        }

        .main-chat {
            color: green;
        }

        .footer {
            min-height: 200px;
            border-top: 1px solid green;
        }

        .footer .ipt {
            width: 100%;
            height: 100%;
            color: green;
            outline: none;
            font-size: 20px;
            padding: 10px;
            box-sizing: border-box;
        }

        .groupList {
            height: 100%;
            overflow: auto;
        }

        .groupList-items {
            height: 50px;
            width: 100%;
            background: #131313;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
        }
    </style>
</head>
<div class="room">
    <div class="left">
        <div class="groupList">

        </div>
    </div>
    <div class="right">
        <header class="header">聊天室</header>
        <main class="main">

        </main>
        <footer class="footer">
            <div class="ipt" contenteditable></div>
        </footer>
    </div>
</div>

<body>
    <script type="module">
        const sendMessage = (message) => {
            const div = document.createElement('div');
            div.className = 'main-chat';
            div.innerText = `${message.user}:${message.text}`;
            main.appendChild(div)
        }
        const groupEl = document.querySelector('.groupList');
        const main = document.querySelector('.main');
        import { io } from "https://cdn.socket.io/4.7.4/socket.io.esm.min.js";
        const name = prompt('请输入你的名字');
        const room = prompt('请输入房间号');
        const socket = io('ws://localhost:3000');
        //键盘按下发送消息
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                const ipt = document.querySelector('.ipt');
                socket.emit('message', {
                    text: ipt.innerText,
                    room: room,
                    user: name
                });
                sendMessage({
                    text: ipt.innerText,
                    user: name,
                })
                ipt.innerText = '';
                
            }
        })
        //连接成功socket
        socket.on('connect', () => {
            socket.emit('join', { name, room });//加入一个房间
            socket.on('message', (message) => {
                sendMessage(message)
            })
            socket.on('groupList', (groupList) => {
                console.log(groupList);
                groupEl.innerHTML = ''
                Object.keys(groupList).forEach(key => {
                    const item = document.createElement('div');
                    item.className = 'groupList-items';
                    item.innerText = `房间名称:${key} 房间人数:${groupList[key].length}`
                    groupEl.appendChild(item)
                })
            })
        })
    </script>
</body>

</html>

nodejs

import http from 'http'
import { Server } from 'socket.io'
import express from 'express'

const app = express()
app.use('*', (req, res, next) => {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "*");
    res.setHeader("Access-Control-Allow-Methods", "*");
    next()
})
const server = http.createServer(app)
const io = new Server(server, {
    cors: true //允许跨域
})
const groupList = {}
/**
 * [{1008:[{name,room,id}]}]
 */
io.on('connection', (socket) => {
    //加入房间
    socket.on('join', ({ name, room }) => {
        socket.join(room)
        if (groupList[room]) {
            groupList[room].push({ name, room, id: socket.id })
        } else {
            groupList[room] = [{ name, room, id: socket.id }]
        }
        socket.emit('message', { user: '管理员', text: `${name}进入了房间` })
        socket.emit('groupList', groupList)
        socket.broadcast.emit('groupList', groupList)
    })
    //发送消息
    socket.on('message', ({ text, room, user }) => {
        socket.broadcast.to(room).emit('message', {
            text,
            user
        })
    })
    //断开链接内置事件
    socket.on('disconnect', () => {
        Object.keys(groupList).forEach(key => {
            let leval = groupList[key].find(item => item.id === socket.id)
            if (leval) {
                socket.broadcast.to(leval.room).emit('message', { user: '管理员', text: `${leval.name}离开了房间` })
            }
            groupList[key] = groupList[key].filter(item => item.id !== socket.id)
        })
        socket.broadcast.emit('groupList', groupList)
    })
});

server.listen(3000, () => {
    console.log('listening on *:3000');
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1512767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

细粒度IP定位参文27(HGNN):Identifying user geolocation(2022年)

[27] F. Zhou, T. Wang, T. Zhong, and G. Trajcevski, “Identifying user geolocation with hierarchical graph neural networks and explainable fusion,” Inf. Fusion, vol. 81, pp. 1–13, 2022. (用层次图、神经网络和可解释的融合来识别用户的地理定位) 论文地址:…

设计模式一 ---单例设计模式(动力节点,JavaSE基础)

设计模式 1.什么是设计模式&#xff1f; 2.设计模式的分类 单例设计模式就是GoF模式中的一种。 3.GoF设计模式的分类&#xff1a; 单例设计模式&#xff1a; 顾名思义&#xff1a;单个实例的设计模式&#xff01;

C#调用Halcon出现尝试读取或写入受保护的内存,这通常指示其他内存已损坏。System.AccessViolationException

一、现象 在C#中调用Halcon&#xff0c;出现异常提示&#xff1a;尝试读取或写入受保护的内存,这通常指示其他内存已损坏。System.AccessViolationException 二、原因 多个线程同时访问Halcon中的某个公共变量&#xff0c;导致程序报错 三、测试 3.1 Halcon代码 其中tsp_width…

【Android】 ClassLoader 知识点提炼

1.Java中的 ClassLoader 1.1 、ClassLoader的类型 Java 中的类加载器主要有两种类型&#xff0c;即系统类加载器和自定义类加载器。其中系统类 加载器包括3种&#xff0c;分别是 Bootstrap ClassLoader、Extensions ClassLoader 和 Application ClassLoader。 1.1.1.Bootstra…

开放原子开源大赛—基于OpenHarmony的团结引擎应用开发赛正式启动!

“基于OpenHarmony的团结引擎应用开发赛”是开放原子全球开源大赛下开设的新兴及应用赛的赛题之一&#xff0c;本次赛题旨在鼓励更多开发者基于OpenHarmony 4.x版本&#xff0c;使用Unity中国团结引擎创造出精彩的游戏与3D应用。 大赛分为“创新游戏”与“创新3D 化应用”两大赛…

全景解析 Partisia Blockchain:以用户为中心的全新数字经济网络

在区块链世界中&#xff0c;以比特币、以太坊网络为代表的主流区块链奠定了该领域早期的基础&#xff0c;并让去中心化、点对点、公开透明以及不可逆成为了该领域固有的意识形态。事实上&#xff0c;过于透明正在成为区块链规模性采用的一大障碍&#xff0c;我们看到 90% 以上的…

【中级软件设计师】上午题05-知识产权

上午题05-知识产权 1 著作权2 专利地域性3 软件著作权4 职务作品5 委托开发6 商业秘密权7 专利权申请8 商标权9 商标注册 【中级软件设计师】上午题05-知识产权 1 著作权 著作权包括著作人身权和著作财产权&#xff0c; 主要记住人身权&#xff1a;发表权、署名权、修改权、保…

欧科云链:比特币现货ETF后时代,链上数据揭示真实供需关系

出品&#xff5c;欧科云链研究院 作者&#xff5c;Hedy Bi 本文于3月11日首发TechFlow深潮&#xff0c;原标题为《比特币现货ETF通过后的2个月&#xff1a;链上数据揭示BTC供不应求》。文中观点纯属笔者基于链上数据进行分析&#xff0c;不构成对任何潜在投资目标的推荐或意见…

20240312-2-贪心算法

贪心算法 是每次只考虑当前最优&#xff0c;目标证明每次是考虑当前最优能够达到局部最优&#xff0c;这就是贪心的思想&#xff0c;一般情况下贪心和排序一起出现&#xff0c;都是先根据条件进行排序&#xff0c;之后基于贪心策略得到最优结果。 面试的时候面试官一般不会出贪…

【Linux进阶之路】HTTP协议

文章目录 一、基本概念1.HTTP2.域名3.默认端口号4.URL 二、请求与响应1.抓包工具2.基本框架3.简易实现3.1 HttpServer3.2 HttpRequest3.2.1 version13.2.2 version23.2.3 version3 总结尾序 一、基本概念 常见的应用层协议&#xff1a; HTTPS (HyperText Transfer Protocol Sec…

RocketMQ部署文档

目录 一、引言 二、简介 三、Linux环境搭建&安装包下载 四、RocketMQ部署服务的简述 五、RocketMQ部署集中集群方式和配置 六、配置&#xff08;注意对应版本&#xff09; 一、引言 适用读者&#xff1a;一切使用RocketMQ的人员。 文章目的&#xff1a;主要介绍Rock…

cmake初识

cmake 什么是软件构建和编译工具cmake安装cmakewindowsLinux 通过cmake编译代码准备CMakeLists.txt注释块状注释cmake_minimum_required:确定cmake的最低版本project&#xff1a;定义工程名称&#xff1a;add_executable&#xff1a;定义工程会生成一个可执行程序准备生成可执行…

JMH287亲测【鸣潮】一键内测风景端V1.0.2已整理并录制视频教学

资源介绍&#xff1a; 否需要虚拟机&#xff1a;否 文件大小&#xff1a;压缩包约15G 支持系统&#xff1a;win7、win10、win11 硬件需求&#xff1a;运行内存16G 4核及以上CPU独立显卡 资源截图&#xff1a; 下载地址&#xff1a; JMH287【鸣潮】一键端 [V1.0.2]

【C++教程从0到1入门编程】第八篇:STL中string类的模拟实现

一、 string类的模拟实现 下面是一个列子 #include <iostream> namespace y {class string{public: //string() //无参构造函数// :_str(nullptr)//{}//string(char* str) //有参构造函数// :_str(str)//{}string():_str(new char[1]){_str[0] \0;}string(c…

性能卓越,服务周到:亚信安慧AntDB的双重优势

亚信安慧AntDB数据库是一种解决实时流数据处理中数据容灾和一致性问题的创新性解决方案。它不仅能够在处理流数据时确保数据的完整性和准确性&#xff0c;还能精确判断数据故障点&#xff0c;从而避免可能的数据损失和错误。AntDB数据库采用先进的技术和算法&#xff0c;能够实…

道路数据下载

下载链接&#xff1a; Geofabrik 下载服务器

Android 配置打包签名信息的两种方法

目录结构如下&#xff1a; 有2种方式&#xff1a; 第一种&#xff0c;直接配置&#xff1a; signingConfigs { debug { storeFile file("app/keystore.properties") storePassword "111111" keyAlias "key" keyPassword "111111" } …

漏洞复现-万户ezOFFICE系列

万户 安全情报,万户ezOFFICE协同管理平台SendFileCheckTemplateEdit-SQL注入漏洞万户OA DocumentEdit_unite.jsp 存在sql注入万户协同办公平台 ezoffice 未授权访问RCExml代码注入 XXE🔪freemarkerService XXE🔪GeneralWeb-xxeofficeserverservlet + attachmentserver RCE…

前端实现 查询包含分页 以及封装table表格 上手即用!

表格组件是 element plus 中的table 又经过了一层封装 封装的table代码在最底下 <div class"box2"><el-radio-group v-model"radio" style"margin-bottom: 16px"><el-radio-button label"1">类型1</el-radio…

2024/3/11打卡分巧克力(第8届蓝桥杯省赛)——二分

题目 儿童节那天有 K 位小朋友到小明家做客。 小明拿出了珍藏的巧克力招待小朋友们。 小明一共有 N 块巧克力&#xff0c;其中第 i 块是 HiWi 的方格组成的长方形。 为了公平起见&#xff0c;小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。 切出的巧克力需要满足&…