websocket和SSE学习记录

news2025/4/21 13:23:23

websocket学习记录

websocket使用场景

  1. 即时聊天
  2. 在线文档协同编辑
  3. 实施地图位置

从开发角度来学习websocket开发

即使通信项目

  1. 通过node建立简单的后端接口,利用fs, path, express
app.get('*', (req, res) => {
  const assetsType = req.url.split('/')[1]
  if (assetsType == 'YouChat'){ // 首页
    const filepath = path.join(path.resolve('./dist'), 'index.html')
    res.sendFile(filepath)
  }
  if (assetsType == 'assets'){ // 客户端资源
    const filepath = path.join(path.resolve('./dist'), req.url)
    res.sendFile(filepath.split('?')[0]) // 去hash
  }
  if (assetsType == 'file'){ // 服务端资源
    const filepath = path.join(path.resolve('./'), req.url)
    res.sendFile(filepath)
  }
  if (assetsType == 'loadImg'){ // 接口
    res.send({ret: 1, data: {portrait, emoticon}})
  }
})

涉及到一个技术点Notification

核心的websocket建立连接的代码
用户注册,将用户的数据进行一个保存,然后初始化websocket的服务,将数据进行一个本地的localstorage的存储

    info.setData('name', userName)
    info.setData('url', sPorSrc)
    initWebSocket()
    localStorage.setItem('YouChatName', userName)
    localStorage.setItem('YouChatPor', sPorSrc)

初始化websocket的服务主要的代码为
2. 建立连接, window.socket.on,使用的是socket.io这个库,socket.io是基于事件驱动的实时通信库, 底层默认使用的是websocket的协议。会自动处理兼容问题,不支持websocket的情况下可以回退到轮询方案。发布订阅模式
剩下的就是逻辑的处理了
连接事件中注册登录时间,监听登录时间,写入数据,监听各种不同的事件,根据事件对数据进行处理。
如下为注册,监听的事件

import info from './info.js'
import view from './view.js'

export default function(){

  window.socket = io()
  window.socket.on('connect', () => { // 连接成功
    const userInfo = {
      name: info.name,
      url: info.url,
      id: window.socket.id
    }
    info.setData('id', window.socket.id)
    window.socket.emit('login', userInfo)
  })
  
  // 登陆
  window.socket.on('login', userInfo => {
    view.drawUserList(userInfo)
  })
  // 获取当前在线列表
  window.socket.on('userList', userList => {
    view.drawUserList(userList)
  })
  // 退出
  window.socket.on('quit', id => {
    view.drawUserList(id)
  })
  // 接收群聊消息
  window.socket.on('sendMessageGroup', message => {
    info.groupMessageList.push(message)
    if (info.member == 'group'){
      view.drawMessageList(info.groupMessageList)
    }else{
      // 提示群聊新消息
      $('.top .group').setAttribute('data-new', 'true')

      let nNewNum = $('.top .group').getAttribute('data-message')
      $('.top .group').setAttribute('data-message', Number(nNewNum) + 1)

      new Notification('收到来自简言的新消息', {
        body: `${message.name}: ${message.text}`,
        icon: message.url
      })
    }
  })
  // 接收私聊消息
  window.socket.on('sendMessageMember', message => {
    if (message.id == info.id){ // 自己的消息回传
      if (info[`member__${message.memberId}`] == undefined) {
        info[`member__${message.memberId}`] = []
      }
      info[`member__${message.memberId}`].push(message)
      view.drawMessageList(info[`member__${message.memberId}`])
    }else{ // 好友私聊消息
      if (info[`member__${message.id}`] == undefined){
        info[`member__${message.id}`] = []
      }
      info[`member__${message.id}`].push(message)
    }

    if (info.member == message.id){
      view.drawMessageList(info[`member__${message.id}`])
    }else{
      // 提示私聊新消息
      if ($(`.item[data-id="${message.id}"]`)){
        $(`.item[data-id="${message.id}"]`).setAttribute('data-new', 'true')

        let nNewNum = $(`.item[data-id="${message.id}"] .item-name`).getAttribute('data-message')
        $(`.item[data-id="${message.id}"] .item-name`).setAttribute('data-message', Number(nNewNum)+1)

        new Notification('收到来自简言的新消息', {
          body: `${message.name}: ${message.text}`,
          icon: message.url
        })
      }
    }
    // userList 消息摘要
    if ($(`.item[data-id="${message.id}"]`)){
      $(`.item[data-id="${message.id}"] .item-text`).innerHTML = message.text || `[收到新灵魂]`
    }
  })
}

其中的各种事件,就是前端逻辑的处理了。这是一个简单的websocket的demo。
学习的是https://github.com/cp0725/YouChat这个库,建议加一个脚本,build: “webpack --config webpack.config.js”, 方便开发调试

心跳检测

WebSocket 心跳检测的本质
本质是通过周期性双向验证维持长连接的活性,解决以下核心问题:

网络中间层的「假性存活」

现象:虽然 TCP 层连接未断开,但防火墙/Nginx 等中间件会主动关闭长时间(如 5 分钟)无数据传输的连接

解法:通过定时发送轻量级探测包(心跳包)重置中间件的空闲计时器

「半开连接」黑洞问题

现象:客户端异常断网后,服务端无法感知连接已失效,持续等待消息

解法:通过双向心跳响应机制,实现连接状态实时探活

与 WebSocket 协议特性的深度结合

协议头优化

心跳包利用 WebSocket 的极简帧头(最低 2 字节),相比 HTTP 头节省 90%+ 流量

扩展协议支持

通过 Sec-WebSocket-Extensions 协商心跳参数(如间隔时间)

可自定义心跳包格式(如携带设备电量、网络类型等元数据)

无跨域特性

心跳机制可跨域运行,无需像 HTTP 轮询那样处理 CORS 问题

http 通过判断 header 中是否包含 Connection: Upgrade 与 Upgrade: websocket 来判断当前是否需要升级到 websocket 协议,除此之外,还有其它 header:

Sec-WebSocket-Key :浏览器随机生成的安全密钥
Sec-WebSocket-Version :WebSocket 协议版本
Sec-WebSocket-Extensions :用于协商本次连接要使用的 WebSocket 扩展
Sec-WebSocket-Protocol :协议
当服务器同意进行 WebSocket 连接时,返回响应码 101

WebSocket 特点:

支持双向通信,实时性更强;
可以发送文本,也可以二进制文件;
协议标识符是 ws,加密后是 wss ;
较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有 2~10 字节(取决于数据包长度),客户端到服务端的的话需要加上额外的 4 字节的掩码。而 HTTP 协议每次通信都需要携带完整的头部;
支持扩展。ws 协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
无跨域问题。

SSE

sse是服务器向客户端推送, 用的是https的长连接,支持自动重连

const express = require('express');
const app = express();
const port = 3000;

// 允许跨域(开发环境用)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  next();
});

// SSE 路由
app.get('/sse-stream', (req, res) => {
  // 设置 SSE 必需的头信息
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });

  // 发送初始数据
  res.write('event: connected\ndata: Welcome!\n\n');

  // 定时发送数据(模拟实时更新)
  let counter = 0;
  const timer = setInterval(() => {
    counter++;
    const data = {
      time: new Date().toISOString(),
      value: counter
    };
    
    // SSE 标准格式(注意换行符)
    res.write(`event: update\n`);
    res.write(`data: ${JSON.stringify(data)}\n\n`);
  }, 1000);

  // 客户端断开时清理
  req.on('close', () => {
    clearInterval(timer);
    res.end();
  });
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
<!DOCTYPE html>
<html>
<body>
  <div id="sse-data"></div>

  <script>
    const eventSource = new EventSource('http://localhost:3000/sse-stream');

    // 通用消息处理(默认事件)
    eventSource.onmessage = (e) => {
      console.log('Default event:', e.data);
    };

    // 自定义事件处理(对应服务端的 event:update)
    eventSource.addEventListener('update', (e) => {
      const data = JSON.parse(e.data);
      document.getElementById('sse-data').innerHTML = `
        Time: ${data.time}<br>
        Counter: ${data.value}
      `;
    });

    // 连接建立事件
    eventSource.addEventListener('connected', (e) => {
      console.log('Connection established:', e.data);
    });

    // 错误处理
    eventSource.onerror = (e) => {
      if (e.eventPhase === EventSource.CLOSED) {
        console.log('Connection closed');
      } else {
        console.error('SSE Error:', e);
      }
      // 自动重连(浏览器默认行为)
    };

    // 页面关闭时断开连接
    window.addEventListener('beforeunload', () => {
      eventSource.close();
    });
  </script>
</body>
</html>

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

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

相关文章

【统计分析120】统计分析120题分享

1-30 判断题 数学模型 指的是通过抽象、简化现实世界的某些现象&#xff0c;利用数学语言来描述他们的结构和行为&#xff0c;做出一些必要的假设&#xff0c;运用适当的数学工具&#xff0c;得到一个数学结论 数学模型&#xff1a;指的是通过抽象、简化现实世界的某些现象&am…

【计量地理学】实验四 主成分分析与莫兰指数

一、实验内容 &#xff08;一&#xff09; 某地区35个城市2004年的7项经济统计指标数据见&#xff08;数据中的“题目1”sheet&#xff09;。 &#xff08;1&#xff09;试用最短距离聚类法对35个城市综合实力进行系统聚类分析&#xff0c;并画出聚类谱系图: 在此次实验内容…

手写call,bind,apply

foo.Mycall(obj,1,2,3) Function.prototype.Mycallfunction(target,...args){if(typeof this!function){throw new TypeError(this is not a function)}// 判断target是否是对象if(targetnull||targetundefined){targetwindow}if(typeof target!object){targetObject(target)}/…

【读书笔记·VLSI电路设计方法解密】问题64:什么是芯片的功耗分析

低功耗设计是一种针对VLSI芯片功耗持续攀升问题的设计策略。随着工艺尺寸微缩&#xff0c;单颗芯片可集成更多元件&#xff0c;导致功耗相应增长。更严峻的是&#xff0c;现代芯片工作频率较二十年前大幅提升&#xff0c;而功耗与频率呈正比关系。因此&#xff0c;芯片功耗突破…

Ubuntu18.04安装Qt5.12

本文介绍了在Ubuntu18.04环境下安装QT QT5.12相关安装包下载地址 https://download.qt.io/archive/qt/5.12/ Linux系统下Qt的离线安装包以.run结尾 (sudo apt-get install open-vm-tools open-vm-tools-desktop解决无法paste的问题) 安装 1.cd命令 终端进入对应的文件夹下面 2.…

max31865典型电路

PT100读取有很多种方案&#xff0c;常用的惠斯通电桥&#xff0c;和专用IC max31865 。 电阻温度检测器(RTD)是一种阻值随温度变化的电阻。铂是最常见、精度最高的测温金属丝材料。铂RTD称为PT-RTD&#xff0c;镍、铜和其它金属亦可用来制造RTD。RTD具有较宽的测温范围&#x…

数据通信学习笔记之OSPF的区域

OSPFArea 用于标识一个 OSPF 的区域 区域是从逻辑上将设备划分为不同的组&#xff0c;每个组用区域号 (Area ID)来标识 OSPF 的区域 ID 是一个 32bit 的非负整数&#xff0c;按点分十进制的形式(与 IPV4 地址的格式一样)呈现&#xff0c;例如 Area0.0.0.1。 为了简便起见&#…

5 提示词工程指南-计划与行动

5 提示词工程指南-计划与行动 计划与行动 Cline 有两种模式: Plan 描述目标和需求、提问与回答、讨论、抽象项目的各个方面、确定技术路线、确定计划 计划与确认相当于架构师,不编写代码Act 按计划编写代码 按照计划编码Plan 模式的本质是构建实际编码前的上下文,Act 的本…

如何一键批量删除多个 Word 文档中的页眉和页脚

在工作中&#xff0c;许多 Word 文档的页眉页脚中包含公司名称、Logo、电话等信息&#xff0c;用于对外宣传。但有时我们需要批量删除这些页眉页脚信息&#xff0c;尤其当信息有误时&#xff0c;手动逐个删除会增加工作量&#xff0c;导致效率低下。本文将介绍一种便捷的方法&a…

QCustomPlot中自定义图层

QCustomPlot 使用图层(QCPLayer)系统来组织绘图元素的绘制顺序和可见性。下面详细介绍如何自定义图层并将可绘制对象关联到特定图层。 1. 理解 QCustomPlot 的图层系统 QCustomPlot 的图层系统具有以下特点&#xff1a; 图层按顺序排列&#xff0c;后绘制的图层会覆盖前面的图…

-实用类-

1. API是什么 2.什么是枚举 &#xff01;有点类似封装&#xff01; 2.包装类 注意&#xff1a; 1.Boolean类构造方法参数为String类型时&#xff0c;若该字符串内容为true(不考虑大小写)&#xff0c;则该Boolean对象表示true&#xff0c;否则表示false 2.当包装类构造方法参…

Spring 事务管理核心机制与传播行为应用

Spring 事务详解 一、Spring 事务简介 Spring 事务管理基于 AOP&#xff08;面向切面编程&#xff09;实现&#xff0c;通过 声明式事务&#xff08;注解或 XML 配置&#xff09;统一管理数据库操作&#xff0c;确保数据一致性。核心目标&#xff1a;保证多个数据库操作的原子…

集合框架(重点)

1. 什么是集合框架 List有序插入对象&#xff0c;对象可重复 Set无序插入对象&#xff0c;对象不可重复&#xff08;重复对象插入只会算一个&#xff09; Map无序插入键值对象&#xff0c;键只唯一&#xff0c;值可多样 &#xff08;这里的有序无序指的是下标&#xff0c;可…

IPv4地址分类与常用网络地址详解

常见的 IPv4 地址分类&#xff1a; 1. A 类地址&#xff08;Class A&#xff09; 范围&#xff1a;0.0.0.0 到 127.255.255.255 默认子网掩码&#xff1a;255.0.0.0 或 /8 用途&#xff1a;通常用于大型网络&#xff0c;例如大型公司、组织。 特点&#xff1a; 网络地址范围…

模拟实现memmove,memcpy,memset

目录 前言 一、模拟实现memmove 代码演示&#xff1a; 二、模拟实现memcpy 代码演示&#xff1a; 三、模拟实现memset 代码演示&#xff1a; 总结 前言 这篇文章主要讲解了库函数的模拟实现&#xff0c;包含memmove&#xff0c;memcpy&#xff0c;memset 一、模拟实现m…

RHCSA Linux 系统文件内容显示2

6. 过滤文件内容显示 grep &#xff08;1&#xff09;功能&#xff1a;在指定普通文件中查找并显示含指定字符串的行&#xff0c;也可与管道符连用。 &#xff08;2&#xff09;格式&#xff1a;grep 选项... 关键字字符串 文件名... &#xff08;3&#xff09;常用选项及说…

【2】Kubernetes 架构总览

Kubernetes 架构总览 主节点与工作节点 主节点 Kubernetes 的主节点&#xff08;Master&#xff09;是组成集群控制平面的关键部分&#xff0c;负责整个集群的调度、状态管理和决策。控制平面由多个核心组件构成&#xff0c;包括&#xff1a; kube-apiserver&#xff1a;集…

Redis下载

目录 安装包 1、使用.msi方式安装 2.使用zip方式安装【推荐方式】 添加环境变量 配置后台运行 启动&#xff1a; 1.startup.cmd的文件 2.cmd窗口运行 3.linux源码安装 &#xff08;1&#xff09;准备安装环境 &#xff08;2&#xff09;上传安装文件 &#xff08;3&…

React 文章 分页

删除功能 携带路由参数跳转到新的路由项 const navigate useNavigate() 根据文章ID条件渲染

OpenCV 图形API(39)图像滤波----同时计算图像在 X 和 Y 方向上的一阶导数函数SobelXY()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::gapi::SobelXY 函数是 OpenCV 的 G-API 模块中用于同时计算图像在 X 和 Y 方向上的一阶导数&#xff08;即 Sobel 边缘检测&#xff09;的一…