ws以及心跳检测机制

3,554 阅读6分钟

websocket以及心跳检测机制

最近的一个项目需要用到 websocket 来实现实时数据的展示,之前的项目基本上没有这个需求所以自己对于 websocket 基本是一知半解的状态。要求当服务器挂起的时候能够检测到挂起中断请求,当服务器正常的时候,要及时连接,因为之前已经有很多前辈的文章对这个有过很详细的论述了,所以我只记录了自己需要学习的地方,本文章不适合作为学习websocket的教程,如果有想要详细的学习websocket教程的请移步阮一峰大神博客,他写的比较详细websocket 教程

websocket简介

  • 什么是websocket?
  • 为什么要有websocket?
  • 怎么使用websocket?
  • 心跳检测机制间歇性校测服务器情况?

什么是websocket?

WebSocket 是一种网络通信协议,更完整的解释是一种基于 TCP 的全双工通信协议,是不是感觉好像解释了又好像没有,WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 通信协议于 2011 年被 IETF 定为标准 RFC 6455,并由 RFC7936 补充规范。WebSocket API 也被 W3C 定为标准。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在websocketAPI 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

为什么要有websocket?

很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每 1 秒),由浏览器对服务器发出 HTTP 请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而 HTTP 请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

http 还有一个比较明显的缺陷就是只能由客户端发起也就是说,如果我想要知道一条结果只能由客户端发起请求,然后服务端返回请求,做不到服务端自动的向客户端推送数据。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。websocket就是这样发明的。 而比较新的技术去做轮询的效果是 Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在 Comet 中,普遍采用的长链接,也会消耗服务器资源。 在这种情况下,HTML5 定义了websocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

websocket 的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

怎么使用websocket?

通过上面的阐述我们大致了解到了为什么要有websocket以及什么是websocket,下面就让我们看一下,我们再代码里面应该怎么去使用websocket

实例化websocket

var ws = new WebSocket("wss://echo.websocket.org");

ws.onopen = function(evt) { 
  console.log("Connection open ..."); 
  ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
  console.log( "Received Message: " + evt.data);
  ws.close();
};

ws.onclose = function(evt) {
  console.log("Connection closed.");
};

websocket相关的API

  • websocket的构造函数
WebSocket 对象作为一个构造函数,
用于新建 WebSocket 实例
var ws = new WebSocket(url);
  • 实例对象的onopen属性,用于指定连接成功后的回调函数
ws.onopen = function () {
  ws.send('Hello Server!');
}
  • 实例对象的onclose属性,用于指定连接关闭后的回调函数。
ws.onclose = function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
};

ws.addEventListener("close", function(event) {
  var code = event.code;
  var reason = event.reason;
  var wasClean = event.wasClean;
  // handle close event
});
  • 实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。
ws.onmessage = function(event) {
  var data = event.data;
  // 处理数据
};

ws.addEventListener("message", function(event) {
  var data = event.data;
  // 处理数据
});
  • 实例对象的send()方法用于向服务器发送数据。
ws.send('your message');
  • 实例对象的onerror属性,用于指定报错时的回调函数。
socket.onerror = function(event) {
  // handle error event
};

socket.addEventListener("error", function(event) {
  // handle error event
});

心跳检测机制检测服务器情况?

有了上面的了解接下来就要实现我这次需要时间的功能了

  1. 实例化一个websocket对象
  2. 监听该对象的报错,发消息,异常信息
  3. 心跳检测机制,定时检测接口是否可以正常的返回,可以就继续操作,如有异常就关闭请求避免多次无用的请求。
 var lockReconnect = false;//避免重复连接
  var wsUrl = "wss://echo.websocket.org";
  var ws;
  var tt;

  function createWebSocket(url)
  {
    try {
      ws = new WebSocket(url);
      init();
    } catch (e) {
      reconnect(url);
    }
  }
  function init()
  {
    ws.onclose = function ()
    {
      console.log("websocket关闭了");
      reconnect(url);
    }
    ws.onopen = function ()
    {
      console.log("websocket打开了");
      heartCheck(url);
    }
    ws.onerror = function ()
    {
      console.log("websocket报错了");
      reconnect(url);
    }
    ws.onmessage = function ()
    {
      //能收到消息说明链接正常
      heartCheck(url);
    }
  }
  function reconnect(url)
  {
    //如果连接被锁定了,就说明当前的链接是正常的
    if (lockReconnnet) {
      return;
    }
    lockReconnnet = true;
    //清除定时器
    tt && clearTimeout(tt);
    tt = setTimeout(() =>
    {
      createWebSocket(url);
      lockReconnnet = false;
    }, 4000)
  }
  var heartCheck = {
    timeout: 3000,
    timeOutObj: null,
    serverTimeOutObj: null,
    start: function ()
    {
      var self = this;
      this.timeOutObj && clearTimeout(this.timeOutObj);
      this.serverTimeOutObj && clearTimeout(this.serverTimeOutObj)
      this.timeOutObj = setTimeout(() =>
      {
        ws.send("发送数据");
        self.serverTimeOutObj = setTimeout(() =>
        {
          ws.onclose();
        }, self.timeout)
      }, self.timeout)
    }
  }
  createWebSocket(wsUrl);

当创建webSocket链接的时候,

  1. 会触发ws.onopen
  2. 心跳检测函数heartCheck
  3. heartCheck给服务端发了请求,如果服务端是通常的,那么就会触发ws.onmessage里面的 heartCheck.start()这次触发会清除掉两个定时器,内层定时器不会被触发了。如果没有在规定时间内返回讯息,那么就会出发内层定时器,连接关闭;
  4. 连接关闭的时候,触发了ws.onclose里面的reconnect函数,重新连接触发1,2,3的步骤

结束语

这只是我的业务需要,中间很多也是参考了前辈的文章才写出来的,websocket在实现实时数据这个方面还是很实用的。如果中间文章有任何问题欢迎评论区随时指正。

本文使用 markdown.com.cn 排版