长连接技术

news2024/11/20 11:46:58

个人学习记录,欢迎指正

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);

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

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

相关文章

TCP-IP 知识汇总

开放式系统互联模型------国际化标准组织ISO提出----协议组&#xff08;协议模型&#xff09; 应用层&#xff1a;接收用户数据&#xff0c;人机交互的接口 表示层&#xff1a;将编码转换为二进制&#xff08;加密、解密&#xff09;---统一格式 会话层&#xff1a;针对传输…

GEE:调用 Assets 中的数据

本文将介绍在 Google Earth Engine&#xff08;GEE&#xff09;平台上调用 Assets 中的数据的方法和代码。 文章目录 一、下载和保存1.1 保存影像数据到Assets1.2 保存矢量数据到Assets 二、调用2.1 调用影像2.2 调用矢量 三、数据路径获取3.1 数据路径 一、下载和保存 下载数…

【php基础】输出、变量、

php基础补充 1. 输出2.和"的区别3.变量3.1变量的命名规则3.2 两个对象指向同一个值3.3 可变变量 4.变量的作用域5. 检测变量 1. 输出 echo: 输出 print: 输出&#xff0c;输出成功返回1 print_r(): 输出数组 var_dump(): 输出数据的详细信息&#xff0c;带有数据类型和数…

【Numpy】练习题100道(51-75题)

&#x1f33b;个人主页&#xff1a;相洋同学 &#x1f947;学习在于行动、总结和坚持&#xff0c;共勉&#xff01; #学习笔记# Git-hub链接 目录 1.题目列表 2.题解 1.题目列表 51. 创建一个表示位置&#xff08;x,y&#xff09;和颜色&#xff08;r,g,b&#xff09;的结…

基于Java中的SSM框架实现万卷图书馆书籍借阅管理系统项目【项目源码+论文说明】计算机毕业设计

基于Java中的SSM框架实现万卷图书馆书籍借阅管理系统演示 摘要 图书管理系统&#xff0c;是一个由人、计算机等组成的能进行管理信息的收集、传递、加工、保存、维护和使用的系统。利用信息控制企业的行为&#xff1b;帮助企业实现其规划目标。 图书馆管理系统&#xff0c;能…

Python错题集-9PermissionError:[Errno 13] (权限错误)

1问题描述 Traceback (most recent call last): File "D:\pycharm\projects\5-《Python数学建模算法与应用》程序和数据\02第2章 Python使用入门\ex2_38_1.py", line 9, in <module> fpd.ExcelWriter(data2_38_3.xlsx) #创建文件对象 File "D:…

2024全新返佣商城分销商城理财商城系统源码 全开源PHP+VUE源码

2023全新返佣商城分销商城理财商城系统源码 全开源PHPVUE源码 程序安装环境要求&#xff1a; nginx1.16 php7.2 mysql5.6 程序全开源PHPVUE源码 有需要测试的老铁&#xff0c;拿去测试吧

每日学习笔记:C++ STL 的无序容器(unordered_set、unordered_map)

定义 特性 能够快速查找元素 操作函数 负载系数 元素个数 / bucket个数 提供哈希函数 提供等价准则 方法一&#xff1a;重写元素的操作符 方法二&#xff1a;自定义函数对象

【PyTorch】进阶学习:一文详细介绍 torch.save() 的应用场景、实战代码示例

【PyTorch】进阶学习&#xff1a;一文详细介绍 torch.save() 的应用场景、实战代码示例 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程…

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…

合作文章(IF=5.6)|16s+RNA-seq+短链脂肪酸检测揭示丁酸梭菌缓解食粪预防兔肠道炎症的新机制

1 研究背景 兔子摄取软性粪便是一种具有营养意义的生理习惯&#xff0c;可提供氨基酸、维生素和其他不能被胃肠道有效吸收的营养物质。除了营养益处外&#xff0c;粪食还能稳定肠道微生物群和功能&#xff0c;这可能具有下游的生理效应&#xff0c;如维持能量稳态、免疫系统发…

2024 谷歌浏览器如何导入导出书签

1.打开谷歌浏览器&#xff0c;点击右上角的菜单按钮&#xff08;三个点组成的图标&#xff09;&#xff0c;在下拉菜单中选择“书签与清单”。 2.选择下一级页签的书签管理器 3.点击右上角的三个小点 4.导出书签 5.导入书签即可

20-消息队列

消息队列 任务与任务之间的通信&#xff0c;任务与中断之间的通信 消息队列是常用于任务之间通信的数据结构。通过消息队列符&#xff0c;任务和任务之间&#xff0c;任务与中断之间可以进行数据的通信。 消息队列的功能 队列又称消息队列&#xff0c;是一种常用于任务间通信…

C++第六弹---类与对象(三)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、类的6个默认成员函数 2、构造函数 2.1、概念 2.2、特性 3、析构函数 3.1、概念 3.2、特性 3.3、调用顺序 总结 1、类的6个默认成员函数…

【STM32 定时器(二)TIM 输入捕获PWM 总结】

STM32定时器之输入捕获总结 OC介绍PWM介绍PWM初始化代码部分开启时钟配置时基单元配置CCR配置GPIO配置复用和重定义功能 开启定时器代码实现 &#xff1a;实现呼吸灯 OC介绍 PWM介绍 PWM参数计算 分辨率越细&#xff0c;分的分量越精细&#xff0c;越稳定&#xff0c;假如它为…

HTML5实现一笔画游戏

HTML5实现一笔画游戏 一笔画问题 一笔画是图论科普中一个著名的问题&#xff0c;它起源于柯尼斯堡七桥问题科普。当时的东普鲁士哥尼斯堡城中有一条河&#xff0c;在这条河上有七座桥&#xff1a; 蓝色的代表河&#xff0c;这条河将城市分开成为四个区域&#xff0c;而七个橙…

华为OD机试 - 单词搜索,找到它 - 回溯(Java 2024 C卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述1、输入2、输出3、说明 四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&a…

Tiktok/抖音旋转验证码识别代码

一、引言 在数字世界的飞速发展中&#xff0c;安全防护成为了一个不容忽视的课题。Tiktok/抖音&#xff0c;作为全球最大的短视频平台之一&#xff0c;每天都有数以亿计的用户活跃在其平台上。为了保护用户的账号安全&#xff0c;Tiktok/抖音引入了一种名为“旋转验证码”的安…

比TODESK好用的软件

比ToDesk更好用的软件&#xff1a;探索远程桌面的新选择 在远程桌面控制领域&#xff0c;ToDesk无疑是一款广受欢迎的软件。然而&#xff0c;随着技术的不断进步&#xff0c;市场上涌现出许多新的竞争者&#xff0c;它们在功能、性能和使用体验上都可能超越ToDesk。本文将介绍…

C语言向C++过渡的基础知识(三)

目录 auto类型变量&#xff08;C11标准支持&#xff09; auto关键字介绍 auto关键字的使用 auto关键字基本使用 auto关键字配合指针和引用 auto关键字不可以推导的场景 基于范围的for循环&#xff08;C11标准支持&#xff09; 基于范围的for循环基础使用 基于范围的fo…