博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

vue+websocket

Posted on 2022-09-05 11:02  地霊殿~三無  阅读(305)  评论(0编辑  收藏  举报

一、websocket是什么

WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被[W3C]定为标准。它算是html5规范中的一个部分,算是一种协议,它借鉴了socket这种思想,为web应用程序客户端和服务端之间(注意是客户端服务端)提供了一种全双工通信机制。同时,它又是一种新的应用层协议,websocket协议是为了提供web应用程序和服务端全双工通信而专门制定的一种应用层协议,通常它表示为:ws://echo.websocket.org/?encoding=text HTTP/1.1,可以看到除了前面的协议名和http不同之外,它的表示地址就是传统的url地址。(ws是不加密的,wss是加密的)

那这种协议是怎么和传统的HTTP1.0或者HTTP/1.1区分开的呢,我从使用过程中截取了一张图片。

image.png

可以看到websocket发起的请求,connection是upgrade,还额外多了upgrade的属性,属性值为websocket,而正常情况短连接的请求,connection都是close的,这才符合http协议下,一个request对应一个response的定义。

服务器也能根据这两个字段,区分websocket请求和其他http请求。

connection: upgrade
urgrade: websocket

简而言之,websocket就是一种新的协议,用来解决实时通信的。首次通信过程借用http的握手动作,建立通道,然后用tcp进行数据传输。

二、为什么要用websocket

在没有websocket之前,开发者们是如何解决这个实时通信的场景的呢。

1、ajax轮询

过程:连接->传输数据->关闭连接

开个定时器,每隔几秒就发起一次请求,询问服务端是否有新数据。

这种方法,一是对服务器压力大(连续请求压力能不大吗),必须要有很快的处理速度,快速响应,会让服务器cpu资源经常被占用,二是总归是有时差(存在间隔时间),要缩短间隔时间做到伪实时通信,那又对服务器压力激增。

2、long poll 长轮询

过程:连接->传输数据->关闭连接

原理和第一点的ajax轮询差不多,都是客户端主动向服务器发起请求,区别就是long poll采用的是阻塞模型,顾名思义,就是会一直占线,直到服务器有消息或者触发超时机制,才会返回response给到客户端,周而复始。

这种方法,发起请求的数量比ajax可少得多了,不过就是会一直占线,这要求服务器必须有很高的并发能力,不然可能会出现,其他正常请求服务器处理不过来的情况。

3、长连接

过程:连接->传输数据->保持连接 -> 传输数据-> ………..->一方关闭连接

HTTP1.1默认是长连接,也就是默认Connection的值就是keep-alive,本次请求响应结束后,TCP连接将仍然保持打开状态,所以浏览器可以继续通过相同的连接发送请求,节省了很多TCP连接建立和断开的消耗,还节约了带宽。

这种长连接的方法,存在几个缺点

a、 keep-alive确实可实现长连接,但是本质上这还是从客户端发起-服务端应答,这种一request一response的模式,不过是省略了每次请求的开启和关闭操作。

b、长连接不代表是永久连接,如果超时了,且连接中没有新消息发出,那这个长连接就会断掉,相应的tcp连接也会被干掉。

4、webscoket

过程:连接->传输数据->保持连接 -> 传输数据-> ………..->一方关闭连接

在WebSocket中,只需要服务器和浏览器通过HTTP协议进行一个握手的动作,然后单独建立一条TCP的通信通道进行数据的传送。WebSocket同HTTP一样也是应用层的协议,但是它是一种双向通信协议,是建立在TCP之上的。

WebSocket的流程大概是以下几步:

a、浏览器、服务器建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。

b、TCP连接成功后,浏览器通过HTTP协议向服务器传送WebSocket支持的版本号等信息。(开始前的HTTP握手)服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据。确保tcp通信通道建立成功。

c、连接成功后,双方通过TCP通道进行数据传输,不需要HTTP协议。 也就是说WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。

相比上面3种,websocket连接成功后,是能双向传输数据的,既可以是服务端主动发起数据推送,也可以是客户端主动向服务端推送心跳包(划重点)。打破了以往web端,只能一问一答,还得是客户端主动发起请求的模式。这对于实时性要求高的场景来说,在项目中接入webscoket,既确保了实时性,对资源要求也不高,无疑是个很好的选择。

websocket目前的缺点就是,低版本浏览器不兼容。(不过现在应该也不会有人用什么ie9或者更低版本吧)

三、怎么在vue项目中使用

要使用webscoket(项目不需要额外引入),那就得对它各种相关状态,api属性都有一定了解。

首先我们先创建一个websocket对象

// 实例化socket,第一个参数必填,第二个是可选的参数,指定子协议用的
    this.socket = new WebSocket(
      url, [protocol]
    )
复制代码

那这个socket对象就有以下属性

调用方法都是this.socket.【属性名】

image.png

还具备了相关事件,可供调用

image.png

发送数据方法

image.png

知道了这些,下面我们就来vue项目中实操一下吧。

# 由于本人仅是前端,本文就不阐述后端websocket的具体实现,仅叙述前端的实现过程

第一步

在data中创建好相关变量

socket: '', // websocket对象
socketStaus: false, // 断线重新标志位,false可发重连请求,true不可
timeoutObj: null, // 心跳机制状态1
serverTimeoutObj: null, // 心跳机制状态2
复制代码

第二步

创建webscoket初始化函数init,在其中进行socket的实例化,和其他相关事件的监听

init: function() {
  if (typeof WebSocket === 'undefined') {
    alert('您的浏览器不支持socket') // ie9及以下版本不支持,判断一下
  } else {
    // 实例化socket
    this.socket = new WebSocket(
      this.config.data[this.GLOBAL_CONST.MONITOR.WS_URL_FOR_WEB],
    ) // 括号中的值是一个url
    // 监听socket连接
    this.socket.onopen = this.open // 关联到具体函数
    // 监听socket错误信息
    this.socket.onerror = this.error // 关联到具体函数
    // 监听socket关闭
    this.socket.onclose = this.close // 关联到具体函数
    // 监听socket消息
    this.socket.onmessage = this.getMessage // 关联到具体函数
  }
},
复制代码

第三步

创建init中相关调用函数

几个函数如下

open: function() {
  this.longstart() // 成功建立连接后,创建心跳检测
},
error: function() {
  // console.log('连接错误,开始重新连接')
  this.reconnect()
},
close: function() {
  console.log('socket已经关闭,开始重新连接')
  this.reconnect()
},
// ws断线重连
reconnect() {
  if (!this.socketStaus) {
    this.socketStaus = true
    setTimeout(() => {
      console.log('重连 实例化socket 前', this.config)
      // 没连接上会一直重连,设置延迟避免请求过多,设了5秒限流
      this.socket = new WebSocket(
        this.config.data[this.GLOBAL_CONST.MONITOR.WS_URL_FOR_WEB],
      )
      // 监听socket连接
      this.socket.onopen = this.open
      // 监听socket错误信息
      this.socket.onerror = this.error
      // 监听socket关闭
      this.socket.onclose = this.close
      // 监听socket消息
      this.socket.onmessage = this.getMessage

      this.socketStaus = false
    }, 5 * 1000)
  }
},
复制代码

还有最重要的接收数据的函数

// ws获取到数据执行方法
getMessage: function(msg) {
  this.longstart() // 拿到数据也要重置心跳机制
  try {
    const data = JSON.parse(msg.data)
    console.log(msg.data, data)
    // 这里写具体逻辑
  } catch (e) {
    console.log('出错了', e)
    return
  }
},
复制代码

心跳函数

// 心跳机制 建议接入该机制
在使用websocket的过程中,有时候会遇到网络断开的情况,但是在网络断开的时候服务
器端并没有触发onclose的事件。这样可能会发生服务器会继续向客户端发送数据,并且
这些数据会丢失。所以需要一种机制来检测客户端和服务端是否处于正常的链接状态。因
此就有了websocket的心跳,检测链接的状态。

longstart() {
  // 1、通过关闭定时器和倒计时进行重置心跳
  clearInterval(this.timeoutObj)
  clearTimeout(this.serverTimeoutObj)
  // 2、每隔30s向后端发送一条商议好的数据
  this.timeoutObj = setInterval(() => {
    console.log('重置监测心跳')
    const data = { // 与后端商量好心跳要传递的值
      packageType: 0
    }
    this.websocketsend(JSON.stringify(data))
    // 3、发送数据 2s后没有接收到返回的数据进行关闭websocket重连
    this.serverTimeoutObj = setTimeout(() => {
      console.log('没有心跳了....')
      this.socket.close()
    }, 2000)
  }, 30 * 1000)
},
复制代码

发送数据的函数

 // 发送数据方法
websocketsend(Data) { // 数据发送
  this.socket.send(Data)
}, 
复制代码

第四步

在合适的时机调用init初始化socket对象

比如我项目是一打开就要连接websocket,那我就在挂载阶段调用。

mounted() {
    this.init()
}
复制代码

第五步

退出前记得销毁相关socket对象和心跳定时器

beforeDestroy() {
    // 1、组件销毁时,关闭与服务器的连接
    if (this.socket) {
      this.socket.close() // 离开路由之后断开websocket连接
    }
    // 销毁心跳定时器
    if (this.timeoutObj) {
      clearInterval(this.timeoutObj)
      this.timeoutObj = null
    }
    if (this.serverTimeoutObj) {
      clearTimeout(this.serverTimeoutObj)
      this.serverTimeoutObj = null
    }
}
复制代码

到此,vue项目已经接入websocket啦,小伙伴们有需要可以试一下。

ps,这里是地霊殿-三無,希望能对你们有所帮助。

Snipaste_2022-07-19_15-30-26.jpg


作者:地霊殿__三無
链接:https://juejin.cn/post/7124942304690831368
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Live2D