长连接技术

个人学习记录,欢迎指正

1.轮询

1.1 轮询的形式

短连接轮询

前端每隔一段时间向服务端发起一次Http请求来获取数据。

const shortPolling = () => {
const intervalHandler = setInterval(() => {fetch('/xxx/yyy').then(response => response.json()).then(response => {/* 自定义短轮询成功标记 */if(response?.code === '1') {/* 自定义工作代码 *//* 结束短轮询 */  clearInterval(intervalHandler)  } })
}, 5000); 
}

长连接轮询

前端向服务端发起一次Http请求,当接收到响应体时重新发起请求来获取数据。

const longPolling = () => {fetch('/xxx/yyy').then(response => response.json()).then(data => {/* 自定义工作代码 *//* 继续长轮询 */longPolling();})
}
1.2 轮询的实现

基于Ajax技术轮询

在1中已经举了关于基于ajax技术实现长轮询和短轮询的例子

基于Iframe的轮询

古老的轮询方式,需要装填数据到jsp,php等形式文档中,没有实现前后端分离开发。

  • 插入: 前端在页面中插入一个隐藏的iframe,iframe的src设置为后端接口地址。

  • 填充: 接口返回数据格式为html,服务端用传统web开发形式向html中插入数据,例如php,jsp。

  • 通信: 返回的html在iframe中运行,通过postMessage与原页面进行通信。

  • 轮询: 原页面收到数据后重新加载iframe进行下次轮询(可以根据策略进行长轮询或短轮询)。

基于Jsonp的轮询

古老的轮询方式,请求失败时无法通过删除标签关闭连接。

  • 插入: 前端在页面中插入一个script标签,src设置为后端接口地址,参数上拼接回调函数名称,当接收到数据后调用之。

  • 填充: 接口返回可执行脚本,脚本最后调用回调函数,便于通知数据已接收到。

  • 通信: 通过回调函数通信。

  • 轮询: 接收到数据后前端重新发起Jsonp轮询,删除标签后插入新的标签继续请求(根据需求进行长轮询或短轮询)。

2.iframe长连接

原理

例如使用http1.x进行通信,服务端在发送响应信息后不关闭信道(在nodejs中即不写 res.end()),每隔一段时间向客户端发送一次消息。这个可以利用服务端持续向iframe输入文档实现。如果使用fetch,xhr,那么无法直接实现,它们只能支持接收一次消息。(目前一般不使用iframe这种古老做法)

在这里插入图片描述

前端代码

<html>
<head><meta charset="UTF-8" />
</head>
<body><div id="display-div"></div><button onclick="handleStartConnect()">开始连接</button><button onclick="handleStopConnect()">断开连接</button><script type="text/javascript">// 开始连接const handleStartConnect = () => {const iframe = document.createElement("iframe");iframe.id = "iframe-connector";iframe.src = "/iframeLongConnection";iframe.style.display = "none";document.body.append(iframe);};// 断开连接const handleStopConnect = () =>document.querySelector("#iframe-connector").remove();// 收集长连接信息  window.addEventListener("message", (event) => {document.querySelector("#display-div").innerHTML = event.data;});</script>
</body>
</html>

服务器代码

let fs = require("fs");// 服务器基本服务
const read = (path, res) => {
// 支持读取html和js
fs.readFile(path, (err, data) => {if (err) console.log(err);else {res.writeHead(200, {"Content-Type":path.slice(-2, path.length) === "js"? "text/javascript": "text/html",});res.write(data);res.end();}
});
};// 输入到iframe中的模板
const getTemplate = () => {
const template = `<script type="text/javascript">window.parent.postMessage(new Date().toLocaleTimeString(), "http://localhost:3000/index.html");</script>
`;
return template;
};// 服务端定时器维持长连接
const circulate = (res) => {
res.writeHead(200, { "Content-Type": "text/html" });
setInterval(() => {res.write(getTemplate());
}, 1000);
};require("http")
.createServer(function (req, res) {// 处理图标if (req.url === "/favicon.ico") res.end();// 长连接测试else if (req.url === "/iframeLongConnection") circulate(res);// 服务器基本服务else read("." + req.url, res);
})
.listen(3000, function (err) {if (err) console.log(err);else console.log("运行成功");
});

4.Websocket长连接

4.1 Websocket实现

4.1 综述

技术综述:

websocket是协议,是对http协议的升级。

websocket基于TCP协议,也是使用80端口。

功能特点:

  • 前端实现简单,只需要建立连接,监听屈指可数的几个事件。
  • 支持全双工通信。服务端和客户端可以互相发送消息。
  • 不局限于web端。其它终端设备或应用程序也可以使用该协议。

4.2 web端Websocket事件和方法

事件描述
open连接建立
close连接关闭
error发生错误
message接收信息
实例方法描述
send发送消息
close关闭连接

4.3 服务端Websocket的事件和方法

服务端实现websocket通常采用第三方库,不同的第三方库对方法和事件的规定各不相同,在此不做具体介绍。

4.4 客户端代码实现

在这里插入图片描述

<html>
<head><meta charset="UTF-8" />
</head>
<body><button onclick="handleBuild()">建立连接</button><button onclick="socket.close()">断开连接</button><button onclick="socket.send(123)">发送一条消息</button><script type="text/javascript">let socket = null;// 连接相关事件监听函数const handleMessage = (event) => alert(event.data);const handleOpen = () => alert("连接成功");const handleError = () => alert("连接错误");const handleClose = () => {alert("连接关闭");socket.removeEventListener("open", handleOpen);socket.removeEventListener("close", handleClose);socket.removeEventListener("error", handleError);socket.removeEventListener("message", handleMessage);};// 建立连接const handleBuild = () => {socket = new WebSocket("ws://localhost:3001/testSocket");socket.addEventListener("open", handleOpen);socket.addEventListener("close", handleClose);socket.addEventListener("error", handleError);socket.addEventListener("message", handleMessage);};// 关闭连接const handleDestroy = () => socket.close();// 发送消息const sendMessage = (message) => socket.send(JSON.stringify(message));</script>
</body>
</html>

4.5 服务端代码实现

const fs = require("fs");
const ws = require("nodejs-websocket");// 基本读写服务
const read = (path, res) => {// 支持读取html和jsfs.readFile(path, (err, data) => {if (err) console.log(err);else {res.writeHead(200, {"Content-Type":path.slice(-2, path.length) === "js"? "text/javascript": "text/html",});res.write(data);res.end();}});
};require("http").createServer(function (req, res) {// 处理图标if (req.url === "/favicon.ico") res.end();else read("." + req.url, res);}).listen(3000, function (err) {if (err) console.log(err);else console.log("运行成功");});const wsServer = ws.createServer((conn) => {// 接收信息conn.on("text", (text) =>conn.sendText(`服务端已收到信息,您的信息是${text}`));// 连接错误conn.on("error", () => console.log("连接错误"));// 连接关闭conn.on("close", () => console.log("连接断开"));
});wsServer.on("connection", () => console.log("新连接建立"));
wsServer.listen(3001);
4.2 Websocket建立与销毁

Http握手

Websocket连接建立需要Http1.1或以上版本的get方法握手,这个过程在浏览器调试栏中无法抓包得到,只能抓包分析Websocket协议。

在前端和后端实现websocket时这个过程和配置对于开发者是无感知的。

  • 请求头:

    字段取值含义是否必设置
    Connectionupgrade希望协议升级必须
    Upgradewebsocket协议应该升级到websocket协议必须
    Sec-Websocket-Key经过base64编码的16字节随机值必须
    Sec-WebSocket-Version版本值websocket版本必须
    Sec-WebSocket-Protocol子协议名称websocket通信时需要的子协议非必须
    Sec-WebSocket-Extensions扩展协议名称websocket通信时的扩展协议非必须
  • 响应头:

    字段取值含义是否必设置
    Sec-WebSocket-AcceptSHA-1哈希值是否支持websocket协议必须
    Sec-WebSocket-Versionwebsocket版本选择支持的websocket版本必须
    Sec-WebSocket-Protocol子协议名称选择支持的子协议非必须
    Sec-WebSocket-Extensions扩展协议名称选择支持的扩展协议名称非必须
  • 响应状态码:

    响应状态码为101时表示可以使用websocket协议

  • Sec-Websocket-Key验证:

    验证过程类似于加密解密。 客户端传给服务端Sec-Websocket-Key,服务端将这个key和一个规定的并且是固定的Websocket魔数(字符串)拼接。之后服务端将这个拼接的字符串输入SHA-1哈希算法,得到哈希值。最后服务端将哈希值返回给客户端,客户端用同样方式解密来判断服务端是否支持websocket协议。

挥手

服务端发出关闭连接的消息或客户端发来关闭连接的消息后将关闭websocket连接

5.SSE长连接

5.1 综述

技术综述:

SSE是一种基于Http协议的技术,不是一种新的协议。

功能特点:

  • 前端需要实现代码不多。
  • 由于只是使用Http协议,因此前后端的配置会比使用Websocket协议简单些。
  • 由于只是使用Http协议,因此只能服务端向前端推送消息,相比Websocket协议的长连接像阉割版。

性能限制:

同一个浏览器同一个域的Http连接最多支持并发6个,如果长时间用SSE技术保持长连接,会降低该域的并发连接数量。

5.2 客户端代码实现

在这里插入图片描述

<html><head><meta charset="UTF-8" /></head><body><div id="message-collector"></div><button onclick="handleBuild()">建立连接</button><button onclick="SSETarget.close()">关闭连接</button><script type="text/javascript">let SSETarget = null;const handleBuild = () => {SSETarget = new EventSource("http://localhost:3002/sseStream");SSETarget.addEventListener("open", () => alert("数据链路可以通信"));SSETarget.addEventListener("error", () => alert("数据链路发生错误"));// 接收数据SSETarget.addEventListener("message",(event) =>(document.querySelector("#message-collector").innerHTML =event.data));// 监听服务端配置的自定义事件SSETarget.addEventListener("testEvent", (event) => console.log(event));};</script></body>
</html>

5.3 服务端代码实现

  • 响应类型: 保证返回的数据类型是 text/event-stream
  • 响应数据结构: 保证换行返回,保证数据是 xxx: yyy形式返回,xxx可取值有 event, data, id等等,分别表示描述事件的响应,描述数据内容的响应,描述数据id的响应。
// 服务器基本读写服务
const read = (path, res) => {// 支持读取html和jsrequire("fs").readFile(path, (err, data) => {if (err) console.log(err);else {res.writeHead(200, {"Content-Type":path.slice(-2, path.length) === "js"? "text/javascript": "text/html",});res.write(data);res.end();}});
};require("http").createServer((req, res) => {// SSE技术服务端简单实现if (req.url === "/sseStream") {res.writeHead(200, {// 必须得返回类型"Content-Type": "text/event-stream"});res.write("retry: 10000\n");// 自定义一个事件res.write("event: testEvent\n");// 在该自定义事件下发送信息给客户端res.write("id: " + "testId\n\n");res.write("data: " + new Date() + "\n\n");interval = setInterval(() => {res.write("event: message\n");res.write("id: " + "messageId\n\n");res.write("data: " + new Date() + "\n\n");}, 1000);req.connection.addListener("close", () => clearInterval(interval), false);} // 处理图标else if (req.url === "/favicon.ico") res.end();// 服务器基本服务else read("." + req.url, res);}).listen(3002);

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

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

相关文章

HarmonyOS NEXT应用开发之跨文件样式复用和组件复用

介绍 本示例主要介绍了跨文件样式复用和组件复用的场景。在应用开发中&#xff0c;我们通常需要使用相同功能和样式的ArkUI组件&#xff0c;例如购物页面中会使用相同样式的Button按钮、Text显示文字&#xff0c;我们常用的方法是抽取公共样式或者封装成一个自定义组件到公共组…

力扣4寻找两个正序数组的中位数

1.实验内容 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 2.实验目的 算法的时间复杂度应该为 O(log (mn)) 。 3.基本思路 碰到时间复杂度要求log的&#xff0c;肯定用二分查找&…

【Markdown】【mermaid】Mermaid流程图基础语法Flowcharts - Basic Syntax

流程图 - 基础语法 流程图简介节点默认节点带文本的节点Unicode 文本Markdown 格式化 流程图方向节点形状圆角矩形节点体育场形节点子程序形节点圆柱形节点圆形节点不对称节点菱形节点六边形节点平行四边形节点另一种平行四边形节点梯形节点另一种梯形节点双圆节点 节点之间的连…

shell编程入门(笔记)

1、shell编程基础&#xff1a; 1.1、shell的解释执行功能 1.2、什么是shell程序&#xff1f; 1.3、shell程序编程的主要内容 1.4、shell程序的第一行 1.5、变量要求 1.6、环境变量和只读变量 1.7、位置参量 1.8、位置参量列表 1.9、数组 2、输入输出 2.1、输入-read命令 2.2…

Pytest用例间参数传递的两种实现方式示例

前言 我们在做接口自动化测试的时候&#xff0c;会经常遇到这种场景&#xff1a;接口A的返回结果中的某个字段&#xff0c;是接口B的某个字段的入参。如果是使用postman&#xff0c;那我们可以通过设置后置变量&#xff0c;然后在需要使用的地方通过{{}}的方式来进行调用。但是…

[LLM]大模型基础知识点--大模型与LLM

1、什么是大模型&#xff1f; 定义&#xff1a;在机器学习领域&#xff0c;"大模型"通常指的是拥有大量参数的深度学习模型。这些模型通常由数十亿甚至数千亿个参数组成。 特点&#xff1a;由于参数众多&#xff0c;这些模型能够从大量数据中学习复杂的模式和关系。…

OJ : 1087 : 获取出生日期(多实例测试)

题目描述 输入某人的18位身份证号&#xff0c;输出其出生日期。 输入 多实例测试。首先输入一个整数n&#xff0c;表示测试实例的个数&#xff0c;然后是n行&#xff0c;每行是一个18位身份证号。 输出 对于输入的每个身份证号&#xff0c;输出一行&#xff0c;即其对应的…

SpringMVC 的运行流程

Spring MVC 是一个基于 MVC 设计模式的 Web 框架&#xff0c;它提供了一种优雅的方式来构建 Web 应用程序&#xff0c;将应用程序的不同部分分离开来&#xff0c;以便更好地管理和维护。了解 Spring MVC 的运行流程对于理解它的工作原理以及在实际项目中的应用非常重要。 1. 请…

银行卡账户交易异常已被限制部分功能,怎么办?

文章目录 I 解决方案1.1 限制原因1.2 防范1.3 案例1.4 用卡安全小知识II 个人账户收款监管规则III 反诈提醒I 解决方案 处理非柜面交易限制,只能到开户行柜台申请解除。异地卡的,需要联系开户行,提供相关资料。有些地方银行的,比如长沙银行,可以使用线上柜台进行审核。先到…

# termux连接云服务器

termux使用 pkg install openssh 连接服务器 ssh root39.100.181.23 安装postgres

不满足软件包要求‘transformers==4.30.2‘, ‘sse-starlette

transformers4.30.2支持的SSE-Starlette版本是0.14.0

Flume入门概述及安装部署

目录 一、Flume概述1.1 Flume定义1.2 Flume基础架构 二、Flume安装部署 一、Flume概述 1.1 Flume定义 Flume是Cloudera提供的一个高可用的&#xff0c;高可靠的&#xff0c;分布式的海量日志采集、聚合和传输的系统。Flume基于流式架构&#xff0c;灵活简单。 1.2 Flume基础…

Python实现计算复读次数(附带源码)

在Python中&#xff0c;可以使用以下几种方法计算复读次数&#xff1a; 方法一&#xff1a;使用count()函数 count()函数用于统计字符串中某个字符或子字符串出现的次数。 示例&#xff1a; Python # 计算字符串中 "a" 出现的次数 count "hello world&quo…

13、Deconstructing Denoising Diffusion Models for Self-Supervised Learning

简介 研究了最初用于图像生成的去噪扩散模型(DDM)的表示学习能力 解构DDM&#xff0c;逐步将其转变为经典的去噪自动编码器(DAE) 探索现代ddm的各个组成部分如何影响自监督表征学习 结论&#xff1a; 只有很少的现代组件对于学习良好的表示是至关重要的&#xff0c;而其他许多…

Linux gcc二进制下载地址

Index of /download/x86_64/releases 待验证&#xff1a; export PATH$HOME/YOURS/gcc-5.4.0/bin:$PATH export LD_LIBRARY_PATH$HOME/YOURS/gcc-5.4.0/lib:$HOME/YOURS/gcc-5.4.0/lib64:$LD_LIBRARY_PATH

【算法刷题day2】Leetcode:977.有序数组的平方、 209.长度最小的子数组、59.螺旋矩阵II

Leetcode:977.有序数组的平方 文档讲解&#xff1a;[代码随想录] 题目链接&#xff1a;977.有序数组的平方 状态&#xff1a;ok 题目&#xff1a; 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序…

web蓝桥杯真题:心愿便利贴

代码及注释&#xff1a; <!-- TODO 待修改的代码 --> <div class"card" :class"item.css" v-for"(item,index) in wishList" :key"index"><div class"header"><img class"close" click&quo…

智能ai写作神器,推荐5个ai在线写作生成器

智能AI写作神器&#xff0c;是不是听起来就很神奇&#xff1f;它们可以帮助我们省去无尽的头疼和煎熬&#xff0c;让我们的文字轻松流畅&#xff0c;幽默风趣。今天&#xff0c;我要向大家推荐五款AI在线写作生成器&#xff0c;让我们一起来看看吧&#xff01; 第一个&#xff…

训练YOLOv9-S

1. YOLOv9-S网络结构 1.1 改前改后的网络结构&#xff08;参数量、计算量&#xff09;对比 修改前调用的yolo.py测试的yolov9.yaml的打印网络情况&#xff0c;包含参数量、计算量 修改后调用的yolo.py测试的yolov9.yaml的打印网络情况&#xff0c;包含参数量、计算量 1.2 …

flutter实现视频播放器,可根据指定视频地址播放、设置声音,进度条拖动,下载等

需要装依赖&#xff1a; gallery_saver: ^2.3.2video_player: ^2.8.3 实现代码 import dart:async; import dart:io;import package:flutter/material.dart; import package:gallery_saver/gallery_saver.dart; import package:path_provider/path_provider.dart; import pac…