长连接技术

个人学习记录,欢迎指正

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和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();
    }
  });
};

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和js
  require("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);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python图像处理【23】分布式图像处理

分布式图像处理 0. 前言1. Dask 简介2. 使用 Dask 进行分布式图像处理2.1 将 RGB 图像块转换为灰度图像块2.2 使用分布式 Sobel 滤波器检测图像边缘 小结系列链接 0. 前言 Python 已逐渐成为数据分析/处理领域中的主要语言&#xff0c;这得益于 Python 丰富的第三方库&#xf…

浅谈RPC的理解

浅谈RPC的理解 前言RPC体系Dubbo架构最后 前言 本文中部分知识涉及Dubbo&#xff0c;需要对Dubbo有一定的理解&#xff0c;且对源码有一定了解 如果不了解&#xff0c;可以参考学习我之前的文章&#xff1a; 浅谈Spring整合Dubbo源码&#xff08;Service和Reference注解部分&am…

C#,图论与图算法,无向图(Graph)回环(Cycle)的不相交集(disjoint)或并集查找(union find)判别算法与源代码

1 回环(Cycle)的不相交集(disjoint)或并集 不相交集数据结构是一种数据结构,它跟踪划分为多个不相交(非重叠)子集的一组元素。联合查找算法是对此类数据结构执行两个有用操作的算法: 查找:确定特定元素所在的子集。这可用于确定两个元素是否在同一子集中。 并集:将…

Linux 时间系统调用

UNIX及LinuxQ的时间系统是由「新纪元时间」Epoch开始计算起。Epoch是指定为1970年1月1日凌晨零点零分零秒&#xff0c;格林威治时间。目前大部份的UNX系统都是用32位来记录时间&#xff0c;正值表示为1970以后&#xff0c;负值则表示1970年以前。 对于当前时间到Epoch 我们用两…

Django项目创建和settings设置

2021版本的pycharm有bug,需要将settings.py中 把BASE_DIR后面的/换成, url:统一资源定位符 互联网上每个文件都有一个唯一的url,它包含的信息指出文件的位置以及浏览器应该怎么处理它 语法: protocol://hostname[:port]/path[?query][#fragment] protocol:协议 hostname:主…

【网络】负载均衡

OSI模型每一层的负载均衡 在OSI模型中&#xff0c;每一层的负载均衡具体如下&#xff1a; 1. 第二层&#xff08;数据链路层&#xff09;&#xff1a;数据链路层的负载均衡通常涉及对MAC地址的操作。在这一层&#xff0c;可以使用虚拟MAC地址技术&#xff0c;外部设备对虚拟MA…

MongoDB 可调节的一致性,其他数据库都不行系列 (白皮书 翻译)--2

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;…

分布式搜索引擎(3)

1.数据聚合 **[聚合&#xff08;](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)[aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)[&#xff09;](https://www.ela…

ASP.NET 服务器控件

目录 一、使用的软件 1、下载 2、新建文件&#xff08;写一个简单的web网页&#xff09; 二、相关知识点 1、Web窗体网页的组件 &#xff08;1&#xff09;可视化组件 &#xff08;2&#xff09;用户接口逻辑 2、Web Form网页的代码模型 &#xff08;1&#xff09;单文件…

Github: Github actions自动化工作原理与多workflow创建和部署

Github actions 1 &#xff09;概述 Github Actions 是Github官方推出的 CI/CD 解决方案 https://docs.githu.com/en/actions 优点 自动发布流程可减少发布过程中手动操作成本&#xff0c;大幅提升ci/cd效率&#xff0c;快速实现项目发布上线 缺点 存在较高的技术门槛需要利用…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:GridRow)

栅格布局可以为布局提供规律性的结构&#xff0c;解决多尺寸多设备的动态布局问题&#xff0c;保证不同设备上各个模块的布局一致性。 栅格容器组件&#xff0c;仅可以和栅格子组件(GridCol)在栅格布局场景中使用。 说明&#xff1a; 该组件从API Version 9开始支持。后续版本…

【Java基础知识总结 | 第三篇】深入理解分析ArrayList源码

文章目录 3.深入理解分析ArrayList源码3.1ArrayList简介3.2ArrayLisy和Vector的区别&#xff1f;3.3ArrayList核心源码解读3.3.1ArrayList存储机制&#xff08;1&#xff09;构造函数&#xff08;2&#xff09;add()方法&#xff08;3&#xff09;新增元素大体流程 3.3.2ArrayL…

每日五道java面试题之mybatis篇(一)

目录&#xff1a; 第一题. MyBatis是什么&#xff1f;第二题. ORM是什么?第三题. 为什么说Mybatis是半自动ORM映射工具&#xff1f;它与全自动的区别在哪里&#xff1f;第四题. 传统JDBC开发存在的问题第五题. JDBC编程有哪些不足之处&#xff0c;MyBatis是如何解决这些问题的…

simulink汽车动力特性模型

1、内容简介 略 76-可以交流、咨询、答疑 simulink汽车动力特性模型 节气门、Gasoline Engine、离合器、作动器 2、内容说明 略 齿轮半径1 0.06; 齿轮半径2 0.072; 有效齿轮半径 2/3*(radius2^3 - radius1^3)/(radius2^2 - radius1^2); 输入传动比 2.1; 输出传动比 1…

代码随想录算法训练营第二十五天 | 216.组合总和III,17.电话号码的字母组合

分段排列&#xff0c;有点像乘法原理&#xff0c;各个区间的顺序确定&#xff0c;但是区间的内部元素不确定&#xff0c;针对各个区间回溯&#xff0c;区间之间相互独立 class Solution { public:vector<string> res;string resStr;vector<string> chooseList;voi…

AI系统性学习03—ChatGPT开发教程

文章目录 1、OpenAI关键概念⭐️2、OpenAI SDK介绍3、OpenAI API KEY&API 认证3.1 REST API安全认证 4、OpenAI模型⭐️4.1 模型分类4.2 GPT44.3 GPT-3.54.4 Embeddings 5、OpenAI快速入门6、Function calling(函数调用)⭐️⭐️⭐️6.1 应用场景6.2 支持function calling的…

HTML静态网页成品作业(HTML+CSS)——世博园介绍(2个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有2个页面。 二、作品演示 三、代…

一维数组选择排序法

1. 作用 将一维随机乱序数组按从小到大顺序排列 2. 原理图 3. 代码 #include <stdio.h> #include <stdlib.h> #include <time.h>int main(void) {int a[5] {0};int len sizeof(a) / sizeof(a[0]);int i 0;int j 0;int minpos 0;int tmp 0;srand(time(…

Word2vec 学习笔记

word2vec 学习笔记 0. 引言1. Word2vec 简介1-1. CBOW1-2. SG 2. 实战 0. 引言 最近研究向量检索&#xff0c;看到有同事使用 MeCab、Doc2Vec&#xff0c;所以把 Word2vec 这块知识学习一下。 1. Word2vec 简介 Word2vec 即 word to vector&#xff0c;顾名思义&#xff0c;…

Python 编程中反斜杠 “\” 的作用:作为续行符和转义字符,处理文件路径和正则表达式时需特别注意。

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ Python 中的反斜杠 \ 可以被用作续行符&#xff0c;它允许你将一行代码分成多行来书写&#xff0c;以提高代码的可读性。这在处理长字符串、复杂的数学表达式或其他需要多行布局的代码时非常有用。 使…