【Node.js】WebSockets

news2024/11/25 2:57:31

概述

WebSockets是一种在浏览器和服务器之间建立持久连接的协议,它允许服务器主动推送数据给客户端,并且在客户端和服务器之间实现双向通信。

  1. 建立连接:客户端通过在JavaScript代码中使用WebSocket对象来建立WebSockets连接。例如:var socket = new WebSocket('ws://example.com/socket');

  2. 协议:WebSockets使用标准的WebSocket协议来进行通信。相对于HTTP协议,WebSocket协议提供了更高效率和更低的延迟。ws和wss协议正对应了http和https。

  3. 服务器支持:为了使用WebSockets,服务器必须支持WebSocket协议。

  4. 事件:WebSocket对象提供了一些事件,用于处理连接的不同阶段和接收到的数据。常见的事件有onopen(连接建立)、onmessage(接收到消息)、onclose(连接关闭)等。

  5. 数据传输:WebSockets可以传输文本和二进制数据。文本数据是以UTF-8编码发送和接收的,而二进制数据使用ArrayBuffer对象。

  6. 安全性:与HTTP协议通过TLS/SSL协议进行加密一样,WebSockets也可以通过wss协议来提供安全的通信。wss://表示通过TLS/SSL加密的WebSockets连接。

  7. 跨域策略:WebSockets默认不受同源策略的限制,可以跨域使用,但仍然会受到服务器的安全策略限制。

可以在浏览器和服务器之间建立稳定的连接,实际应用如聊天应用、实时数据监控等。

基本使用

使用WebSockets进行连接和通信:

首先,在客户端使用WebSocket对象来建立连接:

var socket = new WebSocket('ws://example.com/socket');

// 监听连接建立事件
socket.onopen = function() {
  console.log('WebSocket连接已建立');
  
  // 向服务器发送消息
  socket.send('Hello Server!');
};

// 监听接收到消息事件
socket.onmessage = function(event) {
  var message = event.data;
  console.log('接收到服务器消息:' + message);
};

// 监听连接关闭事件
socket.onclose = function() {
  console.log('WebSocket连接已关闭');
};

在上面的代码中,我们创建了一个WebSocket对象并指定连接的URL。然后我们监听了三个事件:onopen表示连接建立时触发的事件,onmessage表示接收到消息时触发的事件,onclose表示连接关闭时触发的事件。

在连接建立后,我们向服务器发送了一条消息Hello Server!。当服务器向客户端发送消息时,onmessage事件将被触发,并且我们可以在回调函数中处理接收到的消息。

接下来,让我们看一下服务器端的示例代码(以Node.js和Express框架为例):

const express = require('express');
const WebSocket = require('ws');

const app = express();

// 创建WebSocket服务器
const server = require('http').createServer(app);
const wss = new WebSocket.Server({ server });

wss.on('connection', function(socket) {
  console.log('WebSocket连接已建立');

  // 监听客户端发送的消息
  socket.on('message', function(message) {
    console.log('接收到客户端消息:' + message);

    // 向客户端发送消息
    socket.send('Hello Client!');
  });

  // 监听连接关闭事件
  socket.on('close', function() {
    console.log('WebSocket连接已关闭');
  });
});

server.listen(3000, function() {
  console.log('服务器已启动,监听端口3000');
});

在服务器端的代码中,我们使用了ws库创建了一个WebSocket服务器,并监听了connection事件。当有客户端连接到服务器时,connection事件将被触发,并在该回调函数中处理连接过程。

在服务器接收到客户端的消息时,我们输出消息到控制台,并向客户端发送一条回复消息。当连接关闭时,close事件将被触发。

最后,我们在Express应用中创建了一个HTTP服务器,将WebSocket服务器绑定到服务器上,然后启动服务器监听端口3000。

通信小实例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    const ws = new WebSocket('ws://localhost:3000')
    ws.addEventListener('open',()=> {
        console.log('已连接服务器')
        ws.send('我是前端的数据')
    })
    ws.addEventListener('message', ({data})=> {
        console.log(data)
    })
</script>
</body>
</html>
const WebSocket = require('ws')
const socket = new WebSocket.Server({port: 3000});

socket.on('connection',ws=> {
    console.log('我进来了')
    ws.on('message',(data)=> {
        console.log('前端数据:' + data + "。后端返回数据:"+ '我是后端的数据')
    })
    ws.on('close',()=> {
        console.log('溜了溜了')
    })
})

image.png

Socket.io

Socket.io 具有跨平台,实时性,WebSocket 不可连接时自动降级到其他传播机制(如 http 长轮询)等优点。

官方文档:(服务器初始化 | Socket.IO)

npm install socket.io 安装。

聊天室案例

<!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 #2b2d30;
            background: #333;
        }

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

        .header {
            background: rgb(60, 63, 65);
            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: #bcbec4;
        }

        .footer {
            min-height: 200px;
            border-top: 1px solid #4e5157;
        }

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

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

        .groupList-items {
            height: 50px;
            width: 100%;
            background: rgb(67, 69, 74);
            border-bottom: 1px solid #2b2d30;
            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">
    import {io} from "https://cdn.socket.io/4.7.4/socket.io.esm.min.js";

    let name = prompt('请输入你的名字')
    let room = prompt('请输入你要进入的房间')
    const sendMessage = (message) => {
        const div = document.createElement('div');
        div.className = 'main-chat';
        div.innerText = `${message.user}:${message.text}`;
        main.appendChild(div)
    }
    const group = document.querySelector('.groupList');  // 左侧列表的父级
    const main = document.querySelector('.main');  // 消息内容的父级
    const ipt = document.querySelector('.footer .ipt')
    // 希望自己也能收到信息
    const addChart = (msg)=> {
        let item = document.createElement('div')
        item.className = 'main-chat'
        item.innerHTML = `${msg.name}: ${msg.message}`
        main.appendChild(item)
    }
    const socket = io('ws://localhost:3000')  // ws 的地址
    socket.on('connect', () => {
        // 监听回车事件
        document.addEventListener('keydown',e=> {
            if (e.key === 'Enter') {
                const message = ipt.innerText
                socket.emit('message', {name, message, room})
                addChart({name, message})
                ipt.innerText = ''
            }
        })
        // 加入房间
        socket.emit('join', {name, room})
        //监听左侧列表
        socket.on('groupMap', (data) => {
            group.innerHTML = ``
            Object.keys(data).forEach(key=> {
                const item = document.createElement('div')
                item.className = 'groupList-items'
                item.innerHTML = `房间号:${key} 房间人数:${data[key].length}`
                group.appendChild(item)
            })
        })
        //监听发送的消息
        socket.on('message', (data) => {
            addChart(data)
        })
    })
</script>
</body>

</html>
import {createServer} from "http";
import {Server} from "socket.io";

const server = createServer();
const io = new Server(server, {
    cors: true // 允许跨域
});
/**
 * [{name, room, id}, {name, room, id}]
 * @type {{}}
 */
const groupMap = {}

io.on("connection", (socket) => {
    // 前端传过来 name 和 room
    socket.on('join', ({name, room}) => {
        socket.join(room) // 创建一个房间
        if (groupMap[room]) {
            groupMap[room].push({name, room, id: socket.id}) // 已有就 push
        } else {
            groupMap[room] = [{name, room, id: socket.id}]  // 没有就创建
        }
        socket.emit('groupMap', groupMap)
        // 所有人都可以看到
        socket.broadcast.emit('groupMap', groupMap)
        // 管理员发送信息
        socket.broadcast.to(room).emit('message', {
            name: '管理员',
            message: `欢迎${name}进入聊天室`
        })
    })
    // 向前端发消息
    socket.on('message', ({name, message, room}) => {
        // 虽然给别人发送了消息,但是自己收不到
        socket.broadcast.to(room).emit('message', {name, message})
    })
});

server.listen(3000);

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

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

相关文章

KUKA机器人KR FORTEC-2 ultra重型机器人介绍

额定负载在480-800kg的KR FORTEC-2 ultra重型机器人专为快速精确处理高惯量的大型部件的工艺而设计&#xff0c;双支撑连接臂使性能更强&#xff0c;并可以在紧凑的空间内保持优异性能。在工业生产中&#xff0c;工件的转动惯量越大&#xff0c;对机器人的有效载荷和臂展要求越…

安全SCDN的威胁情报库对DDOS防护有什么好处

目前网络攻击事件频频发生&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击已成为各种企业&#xff08;小到区域性小公司大到各种跨国公司&#xff09;的主要威胁&#xff0c;DDoS 攻击可能会对企业造成重大损害和破坏&#xff0c;比如对目标公司的业务造成产生不利…

探索父进程和子进程

文章目录 通过系统调用查看进程PID父进程、子进程 通过系统调用创建进程-fork初识为什么fork给父进程返回子进程的PID&#xff0c;给子进程返回0fork函数如何做到返回两个值一个变量为什么同时会有两个返回值&#xff1f;bash总结 通过系统调用查看进程PID getpid()函数可以获…

win10配置CLion2022+ubuntu20.04远程部署

背景 在博文ubunut搭建aarch64 cuda交叉编译环境记录中&#xff0c;使用的ubuntu20.04虚拟机安装eclipse来交叉编译aarch64的程序&#xff0c;然后发送到jetson板子上执行。开发一段时间后发现eclipse IDE使用起来不太便捷&#xff0c;因此&#xff0c;考虑使用CLion IDE&…

接口自动化框架搭建(四):pytest的使用

1&#xff0c;使用说明 网上资料比较多&#xff0c;我这边就简单写下 1&#xff0c;目录结构 2&#xff0c;test_1.py创建两条测试用例 def test_1():print(test1)def test_2():print(test2)3&#xff0c;在pycharm中执行 4&#xff0c;执行结果&#xff1a; 2&#xff0…

新能源汽车充电桩常见类型及充电桩站场的智能监管方案

随着新能源汽车市场的迅猛发展&#xff0c;充电桩作为支持其运行的基础设施&#xff0c;也呈现出多样化的类型。这些充电桩不仅在外形和功能上存在差异&#xff0c;更在充电速度、充电方式以及使用场景等方面展现出独特的优势。 一、充电桩类型及区别 1、慢充桩&#xff08;交…

《算法笔记》系列----质数的判断(埃氏筛法)

目录 一、朴素算法 二、埃氏筛法 1、与朴素算法对比 2、算法介绍 3、例题即代码实现 一、朴素算法 从素数的定义中可以知道&#xff0c;一个整数n要被判断为素数&#xff0c;需要判断n是否能被2.3.n- 1中的一个整除。只2&#xff0c;3..n- 1都不能整除n&#xff0c;n才能…

Coursera自然语言处理专项课程03:Natural Language Processing with Sequence Models笔记 Week02

Natural Language Processing with Sequence Models Course Certificate 本文是https://www.coursera.org/learn/sequence-models-in-nlp 这门课程的学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 Natural Language Processing with Sequence ModelsWeek 02…

springcloud基本使用(搭建eureka服务端)

创建springbootmaven项目 next next finish创建成功 删除项目下所有文件目录&#xff0c;只保留pox.xml文件 父项目中的依赖&#xff1a; springboot依赖&#xff1a; <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-s…

增强现实(AR)的开发工具

增强现实&#xff08;AR&#xff09;的开发工具涵盖了一系列的软件和平台&#xff0c;它们可以帮助开发者创造出能够将虚拟内容融入现实世界的应用程序。以下是一些在AR领域内广泛使用的开发工具。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎…

虚拟机 centos 安装后与主机 ip保持一致

1、安装时 网络模式 悬着自动检测 &#xff08;桥接&#xff09; 2、打开网络 这里如果没有打开 就去 编辑 该文件。把ONBOOTno 改为yes 后 vim /etc/sysconfig/network-scripts/ifcfg-ens160 刷新配置 systemctl restart network 再查看addr 与本机 192.168.31.xx 在同…

HN热帖|替换Redis的一场赛跑

3 月 21 日&#xff0c; Redis Ltd. 宣布了一项重大决定&#xff1a;Redis “内存数据存储”项目从 Redis 7.4 版本开始将以非自由的、源代码可用的许可证发布。这一消息并不受欢迎&#xff0c;但也并非完全意外。这次的变化的不同寻常之处是市面上已经有了多个 Redis 替代品可…

1.Netty介绍及NIO三大组件

Netty网络编程Netty的底层是NIO&#xff08;非阻塞IO&#xff09;&#xff0c;常用的多线程和线程池使用的是阻塞IO&#xff0c;其效率并不高。支持高并发&#xff0c;性能好高性能的服务端程序、客户端程序 NIO三大组件 一、Channel 读写数据的双向传输通道 常见的传输通道…

React Native框架开发APP,安装免费的图标库(react-native-vector-icons)并使用详解

一、安装图标库 要使用免费的图标库&#xff0c;你可以使用 React Native Vector Icons 库。 首先&#xff0c;确保你已经安装了 react-native-vector-icons&#xff1a; npm install --save react-native-vector-iconsnpm install --save-dev types/react-native-vector-ic…

深入理解数据结构第一弹——二叉树(1)——堆

前言&#xff1a; 在前面我们已经学习了数据结构的基础操作&#xff1a;顺序表和链表及其相关内容&#xff0c;今天我们来学一点有些难度的知识——数据结构中的二叉树&#xff0c;今天我们先来学习二叉树中堆的知识&#xff0c;这部分内容还是非常有意思的&#xff0c;下面我们…

Collection与数据结构 链表与LinkedList(二):链表精选OJ例题(上)

1. 删除链表中所有值为val结点 OJ链接 class Solution {public ListNode removeElements(ListNode head, int val) {if(head null){return head;}ListNode pre head;ListNode cur head.next;while(cur ! null){if(cur.val val){pre.next cur.next;}else{pre pre.next;…

天空卫士SASE 2.0:赋能您的数智安全

在这个以数据为核心的时代&#xff0c;企业的安全防线正面临着空前的挑战。随着对网络安全和数字化协作的需求不断攀升&#xff0c;企业如何在确保数据安全的前提下&#xff0c;维持业务的高效运转&#xff0c;成为了一个亟待解决的问题。企业管理者亟需一种集网络安全、云服务…

京东云16核64G云服务器租用优惠价格500元1个月,35M带宽

京东云16核64G云服务器租用优惠价格500元1个月、5168元一年&#xff0c;35M带宽&#xff0c;配置为&#xff1a;16C64G-450G SSD系统盘-35M带宽-8000G月流量 华北-北京&#xff0c;京东云活动页面 yunfuwuqiba.com/go/jd 活动链接打开如下图&#xff1a; 京东云16核64G云服务器…

SD-WAN安全策略,保护企业网络的新边界

随着企业的数字化转型和网络架构的演变&#xff0c;SD-WAN&#xff08;软件定义广域网&#xff09;作为一种新兴的网络技术&#xff0c;正在逐渐取代传统的基于硬件的广域网架构。然而&#xff0c;随之而来的安全威胁也在增加&#xff0c;因此在部署 SD-WAN时&#xff0c;制定合…

用Unity制作正六边形拼成的地面

目录 效果演示 1.在Unity中创建正六边形 2.创建一个用于管理正六边形的类 3.创建一个用于管理正六边形地面的类 4.创建一个空对象并将游戏控制脚本挂上 5.设置正六边形碰撞所需组件 6.创建正六边形行为触发脚本并挂上 7.创建圆柱体——田伯光 8.创建圆柱体移动脚本 运…