vue中使用WebSocket心跳机制与Linux中的心跳机制

WebSocket心跳机制

 

一、WebSocket简介

WebSocket是HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

二、WebSocket事件与方法

1、创建WebSocket实例

    var socketObj;
    if ("WebSocket" in window) {
      socketObj = new WebSocket(webSocketLink);
    } else if ("MozWebSocket" in window) {
      socketObj = new MozWebSocket(webSocketLink);
    }

 

2、WebSocket 事件

 

3、WebSocket 方法

 

三、WebSocket的心跳重连机制

1、问题

(1)websocket在连接后,如果长时间服务端和客户端不发消息,服务端会把websocket给断开。
(2)存在网络忽然断开的情况,这时服务器端并没有触发onclose的事件。服务器会继续向客户端发送多余的信息,这些数据会丢失。

2、心跳重连机制

为了解决上面的问题,就需要⼀种机制来检测客户端和服务端是否处于正常的连接状态。因此就有了websocket的心跳机制。

⼼跳机制是客户端每隔⼀段时间会向服务端发送⼀个数据包,告诉服务端自己还活着,同时客户端会根据服务端是否会回传⼀个数据包来确定服务端是否还活着。
如果客户端没有收到回复,表示websocket断开连接或者网络出现问题,就需要重连。

四、实际使用

详细代码如下:

<template>
  <div></div>
</template>
<script>
export default {
  data() {
    return {
      // websocket相关
      socketObj: "", // websocket实例对象
      //心跳检测
      heartCheck: {
        vueThis: this, // vue实例
        timeout: 10000, // 超时时间
        timeoutObj: null, // 计时器对象——向后端发送心跳检测
        serverTimeoutObj: null, // 计时器对象——等待后端心跳检测的回复
        // 心跳检测重置
        reset: function () {
          clearTimeout(this.timeoutObj);
          clearTimeout(this.serverTimeoutObj);
          return this;
        },
        // 心跳检测启动
        start: function () {
          this.timeoutObj && clearTimeout(this.timeoutObj);
          this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
          this.timeoutObj = setTimeout(() => {
            // 这里向后端发送一个心跳检测,后端收到后,会返回一个心跳回复
            this.vueThis.socketObj.send("HeartBeat");
            console.log("发送心跳检测");
            this.serverTimeoutObj = setTimeout(() => {
              // 如果超过一定时间还没重置计时器,说明websocket与后端断开了
              console.log("未收到心跳检测回复");
              // 关闭WebSocket
              this.vueThis.socketObj.close();
            }, this.timeout);
          }, this.timeout);
        },
      },
      socketReconnectTimer: null, // 计时器对象——重连
      socketReconnectLock: false, // WebSocket重连的锁
      socketLeaveFlag: false, // 离开标记(解决 退出登录再登录 时出现的 多次相同推送 问题,出现的本质是多次建立了WebSocket连接)
    };
  },
  created() {
    console.log("离开标记", this.socketLeaveFlag);
  },
  mounted() {
    // websocket启动
    this.createWebSocket();
  },
  destroyed() {
    // 离开标记
    this.socketLeaveFlag = true;
    // 关闭WebSocket
    this.socketObj.close();
  },
  methods: {
    // websocket启动
    createWebSocket() {
      let webSocketLink = "wss://uat.sssyin.cn/ws-reservation"; // webSocket地址
      // console.log(webSocketLink);
      try {
        if ("WebSocket" in window) {
          this.socketObj = new WebSocket(webSocketLink);
        } else if ("MozWebSocket" in window) {
          this.socketObj = new MozWebSocket(webSocketLink);
        }
        // websocket事件绑定
        this.socketEventBind();
      } catch (e) {
        console.log("catch" + e);
        // websocket重连
        this.socketReconnect();
      }
    },
    // websocket事件绑定
    socketEventBind() {
      // 连接成功建立的回调
      this.socketObj.onopen = this.onopenCallback;
      // 连接发生错误的回调
      this.socketObj.onerror = this.onerrorCallback;
      // 连接关闭的回调
      this.socketObj.onclose = this.oncloseCallback;
      // 向后端发送数据的回调
      this.socketObj.onsend = this.onsendCallback;
      // 接收到消息的回调
      this.socketObj.onmessage = this.getMessageCallback;

      //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
      window.onbeforeunload = () => {
        this.socketObj.close();
      };
    },
    // websocket重连
    socketReconnect() {
      if (this.socketReconnectLock) {
        return;
      }
      this.socketReconnectLock = true;
      this.socketReconnectTimer && clearTimeout(this.socketReconnectTimer);
      this.socketReconnectTimer = setTimeout(() => {
        console.log("WebSocket:重连中...");
        this.socketReconnectLock = false;
        // websocket启动
        this.createWebSocket();
      }, 4000);
    },
    // 连接成功建立的回调
    onopenCallback: function (event) {
      console.log("WebSocket:已连接");
      // 心跳检测重置
      this.heartCheck.reset().start();
    },
    // 连接发生错误的回调
    onerrorCallback: function (event) {
      console.log("WebSocket:发生错误");
      // websocket重连
      this.socketReconnect();
    },
    // 连接关闭的回调
    oncloseCallback: function (event) {
      console.log("WebSocket:已关闭");
      // 心跳检测重置
      this.heartCheck.reset();
      if (!this.socketLeaveFlag) {
        // 没有离开——重连
        // websocket重连
        this.socketReconnect();
      }
    },
    // 向后端发送数据的回调
    onsendCallback: function () {
      console.log("WebSocket:发送信息给后端");
    },
    // 接收到消息的回调
    getMessageCallback: function (msg) {
      // console.log(msg);
      console.log(msg.data);
      if (msg.data.indexOf("HeartBeat") > -1) {
        // 心跳回复——心跳检测重置
        // 收到心跳检测回复就说明连接正常
        console.log("收到心跳检测回复");
        // 心跳检测重置
        this.heartCheck.reset().start();
      } else {
        // 普通推送——正常处理
        console.log("收到推送消息");
        let data = JSON.parse(msg.data);
        // 相关处理
        console.log(data);
      }
    },
  },
};
</script>

 

Linux中的心跳机制方案

 

 

心跳机制时,发送心跳包后判断设备是否离线

等待响应

发送心跳包后,需要等待对方设备的响应。可以设置一个合理的超时时间,如果在这个时间内没有收到响应,则可能表明对方设备有问题。

超时处理

如果在设定的超时时间内没有收到响应,应该认为对方设备可能离线或出现故障。这时,可以采取进一步的措施,如重试发送心跳包、记录日志、发送告警、尝试重新建立连接等。

重试机制

在确定对方设备离线之前,可以实施一定的重试机制。例如,连续几次心跳包均未得到响应后才判断为离线。这有助于避免因网络短暂抖动而错误地判断设备离线。

心跳包的响应内容

心跳响应不仅是一个简单的确认,有时可以包含设备的状态信息。通过分析这些信息,可以更准确地判断设备的健康状况。

多点检测

如果应用场景允许,可以从多个节点发送心跳包,以增加检测的可靠性。如果所有节点都无法接收到响应,那么可以更确定地判断设备离线。

整合监控系统

在大型系统中,心跳检测通常与监控系统整合,以实现更全面的状态监控和告警机制。

Netty保活机制

TCP层面的保活机制

TCP 协议本身提供了一个保活机制,通过在长时间未收到数据时向对端发送探测报文,以检测连接的状态。在 Netty 中,可以通过设置 childOption(ChannelOption.SO_KEEPALIVE, true) 来启用 TCP 层面的保活机制。

TCP长连接下,客户端和服务器若长时间无数据交互情况下,若一方出现异常情况关闭连接,抑或是连接中间路由出于某种机制断开连接,而此时另一方不知道对方状态而一直维护连接,浪费系统资源的同时,也会引起下次数据交互时出错。为了解决此问题,引入了TCP KeepAlive机制(并非标准规范,但操作系统一旦实现,默认情况下须为关闭,可以被上层应用开启和关闭)。其基本原理是在此机制开启时,当长连接无数据交互一定时间间隔时,连接的一方会向对方发送保活探测包,如连接仍正常,对方将对此确认回应。

TCP KeepAlive参数

KeepAlive为操作系统层面的参数.
tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测包的间隔,即允许的持续空闲时长,或者说每次正常发送心跳的周期,默认值为7200s(2h)。

tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
在tcp_keepalive_time之后,最大允许发送保活探测包的次数,到达此次数后直接放弃尝试,并关闭连接,默认值为9(次)。

tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
在tcp_keepalive_time之后,没有接收到对方确认,继续发送保活探测包的发送频率,默认值为75s。

sysctl net.ipv4.tcp_keepalive_time
sysctl net.ipv4.tcp_keepalive_intvl
sysctl net.ipv4.tcp_keepalive_probes

image

设置keepalive参数

vi /etc/sysctl.conf

# 数据交互空闲600秒后发送保活数据
net.ipv4.tcp_keepalive_time=600
# 如果没有收到对方确认,继续发送保活探测包,间隔为60秒
net.ipv4.net.ipv4.tcp_keepalive_intvl=60
# 最大允许发送保活探测包的次数,到达此次数后直接放弃尝试,并关闭连接
net.ipv4.net.ipv4.tcp_keepalive_probes=20

cat /etc/sysctl.conf
# 刷新配置
sysctl -p
查看TCP连接
netstat -anutp

参数含义:

-a 显示所有
-n 以ip形式显示当前建立的有效连接和端口
-u 显示UDP协议
-t 显示TCP协议
-p 显示对应PID与程序名

TCP KeepAlive报文格式

TCP KeepAlive探测报文是一种没有任何数据,同时ACK标志被置上的报文,报文中的序列号为上次发生数据交互时TCP报文序列号减1。比如上次本端和对端数据交互的最后时刻,对端回应给本端的ACK报文序列号为 N(即下次本端向对端发送数据,序列号应该为N),则本端向对端发送的保活探测报文序列号应该为 N-1。

TCP KeepAlive机制 的作用 是检测连接的有无(死活),但无法检测连接是否有效,如断网的时候。“连接有效”的定义 = 双方具备发送和接收消息的能力
KeepAlive机制无法代替心跳机制,需要在应用层自己实现心跳机制以检测长连接的有效性,从而高效维持长连接
Keep-Alive机制不会强制切断连接,如果连接存在但是一直不发生数据交互。Keep-Alive不会切断连接。而应用层实现的心跳检测 heartbeat_check 即便连接存在,但不产生数据交互的情况下,依然会强制切断连接。

IdleStateHandler

Netty 提供了一个名为 IdleStateHandler 的处理器,用于在一段时间内没有读取到数据或写入数据时触发事件。你可以通过将 IdleStateHandler 添加到 ChannelPipeline 中来实现自定义的空闲状态处理逻辑。这样就可以及时地检测连接的空闲状态,执行相应的处理操作,比如发送心跳消息或关闭连接。

定时任务

除了 IdleStateHandler 外,你还可以使用 Netty 提供的定时任务功能来实现保活机制。通过定时任务,你可以周期性地向对端发送心跳消息,以检测连接的状态。这种方式更加灵活,可以根据实际需求自定义心跳间隔和心跳消息内容

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

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

相关文章

为什么总是卡在验证真人这里无法通过验证?

最近总是在浏览某些网站的时候卡在这个“确认你是真人”的验证页面&#xff0c;无法通过真人验证&#xff0c;这是怎么回事儿&#xff1f;如何解决呢&#xff1f; 首先&#xff0c;出现这个“确认您是真人”的验证一般都是这个网站使用了 CloudFlare 的安全防护 WAF 规则才会出…

【每日刷题】Day54

【每日刷题】Day54 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 575. 分糖果 - 力扣&#xff08;LeetCode&#xff09; 2. 147. 对链表进行插入排序 - 力扣&#xf…

Ubuntu 24.04 LTS 安装Docker

1 更新软件包索引&#xff1a; sudo apt-get update 2 安装必要的软件包&#xff0c;以允许apt通过HTTPS使用仓库&#xff1a; sudo apt-get install apt-transport-https ca-certificates curl software-properties-common 3 添加Docker的官方GPG密钥&#xff1a; curl -fs…

【WEEK14】 【DAY5】Swagger Part 3【English Version】

2024.5.31 Friday Following up on【WEEK14】 【DAY4】Swagger Part 2【English Version】 Contents 16.6. Configure API Groups16.6.1. Modify SwaggerConfig.java16.6.2. Restart 16.7. Entity Configuration16.7.1. Create a new pojo folder16.7.2. Modify HelloControlle…

RDD与Java实战:学生列表,先按性别降序,再按年龄降序排列

文章目录 Scala RDD 实现Java 实现实战总结 在本实战任务中&#xff0c;我们的目标是对学生列表进行排序&#xff0c;排序规则是先按性别降序排列&#xff0c;再按年龄降序排列。我们提供了两种实现方式&#xff1a;使用Scala的RDD&#xff08;弹性分布式数据集&#xff09;和…

牛客网刷题 | BC109 正斜线形图案

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 KiKi学习了循环&am…

今日好料推荐(这就是会计)

今日好料推荐&#xff08;这就是会计&#xff09; 参考资料在文末获取&#xff0c;关注我&#xff0c;获取优质资源。 这就是会计&#xff1a;资本市场的会计逻辑 是一本由中国会计专家编写的书籍&#xff0c;旨在深入探讨会计在资本市场中的核心作用及其运作逻辑。作为一本…

HTTPS加密

一.加密是什么 加密就是把明文(要传输的信息)进行一系列的变换,生成密文. 有加密就有解密,解密就是把密文进行一系列的变换,生成明文. 在这个加密和解密过程中,往往需要一个或多个中间数据,辅助进行这个过程,这样的数据称为密钥. 加密解密到如今已经发展成了一个独立的学科 : 密…

AtCoder Beginner Contest 356 A~E(F更新中...)

A.Subsegment Reverse 题意 给出三个正整数 N , L , R N, L, R N,L,R。 对于一个序列 A ( 1 , 2 , … , N ) A (1, 2, \ldots, N) A(1,2,…,N)&#xff0c;请你输出翻转了 L ∼ R L \sim R L∼R之间数字后得到的序列。 分析 使用循环进行翻转即可。 代码 #include <…

学工管理系统有什么作用

学生信息办理系统是针对学校学生处的很多作业处理作业而开发的办理软件&#xff0c;首要用于学校学生信息办理&#xff0c;整体使命是完成学生信息联系的体系化、科学化、标准化和自动化&#xff0c;其首要使命是用手机和计算机对学生各种信息进行日常办理&#xff0c;如查询、…

Ubuntu 20.04 LTS配置JDK、Git

一、配置JDK 1.1 更新系统 执行以下命令 sudo apt update 出现以下界面即为安装成功 1.2 安装openjdk-11-jdk Ubuntu20.04中没有默认JDK&#xff0c;执行以下指令安装&#xff0c;默认会自动配置一些必要环境变量 sudo apt install openjdk-11-jdk 1.3 配置环境变量&…

CMake编译安装、生成可执行程序、生成静态动态库以及静态动态库的链接

1 CMake介绍 CMake是一个开源的、跨平台的构建系统&#xff0c;用于管理软件从源代码到可执行文件的整个构建过程。它最初由Kitware公司为ITK&#xff08;Insight Segmentation and Registration Toolkit&#xff09;和VTK&#xff08;Visualization Toolkit&#xff09;等开源…

TimeDao-一篇文章了解清楚Subspace项目

1 项目简介 什么是Subspace网络&#xff1f; Subspace是为下一波加密创建者构建的第四代区块链。旨在实现web3规模扩容。 Subspace允许开发者以互联网规模运行 Web3 应用。它提供了一个简单的接口&#xff0c;用于快速部署按需求自动扩展的多链去中心化应用。Subspace由一个…

Python06 条件判断语句

Python 条件判断语句 Python 条件判断语句格式1if 条件 :else:格式2if 条件 :elif条件 :else:三目: second_max num1 if 条件语句 else num2# 快捷键: tab 整体向右移动一个水平制表符&#xff0c;shift tab 整体向左移动一个水平制表符 num1 10 num2 20 if num2 > num…

每日5题Day15 - LeetCode 71 - 75

每一步向前都是向自己的梦想更近一步&#xff0c;坚持不懈&#xff0c;勇往直前&#xff01; 第一题&#xff1a;71. 简化路径 - 力扣&#xff08;LeetCode&#xff09; class Solution {public String simplifyPath(String path) {Deque<String> stack new LinkedList…

Java17 --- SpringCloud之seate

目录 一、创建seata需要的mysql数据库表 二、修改seata的配置文件 三、启动nacos及seata 四、创建需要的数据库及表 一、创建seata需要的mysql数据库表 CREATE DATABASE seata;CREATE TABLE IF NOT EXISTS global_table(xid VARCHAR(128) NOT NULL,…

电影APP需求规格说明书示范

电影APP需求规格说明书示范 目录结构参考1 引言1.1编写目的1.2背景1.3项目目标1.4 概述 2 整体说明2.1 用例模型2.2 产品功能2.3 用户特点2.4 需求分配 3 具体需求3.1用例描述3.2用例细化 4 支持信息 目录结构参考 计算机软件需求规格说明规范 标准号&#xff1a;GB/T 9385-20…

Jmeter参数化

Jmeter参数化 本质&#xff1a;使用参数的方式来替代脚本中的固定的测试数据 实现方式&#xff1a; 定义变量&#xff08;最基础&#xff09; 文件定义的方式&#xff08;所有测试数据都是固定的情况下&#xff09; 数据库的方式&#xff08;灵活&#xff09; 函数方式&am…

详解 Spark核心编程之广播变量

广播变量是分布式共享只读变量 一、广播变量功能 ​ 广播变量用来将一个较大的数据对象发送到 Executor 并保存在内存中&#xff0c;同一个 Executor 中的所有 Task 都可以读取且只能读取广播变量中的数据&#xff0c;从而达到共享的目的&#xff0c;避免 Executor 中存在大量…

java—MyBatis框架

简介 什么是 MyBatis&#xff1f; MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&…