你会用到的websocket

163 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

websocket

一,什么是websocket

WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)
它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的
Websocket是一个持久化的协议

二,websocket的原理

websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方 便它们之间的通信
在websocket出现之前,web交互一般是基于http协议的短连接或者长连接
websocket是一种全新的协议,不属于http无状态协议,协议名为"ws"

三,websocket与http的关系

相同点:
都是基于tcp的,都是可靠性传输协议
都是应用层协议

不同点:
WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
HTTP是单向的
WebSocket是需要浏览器和服务器握手进行建立连接的
而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接

四,为什么使用websocket协议

通常情况下,客户端访问服务器端使用的是http或https协议,客户端发起请求,服务器端处理请求然后返回数据,客户端再呈现页面,

但是如果想要获取实时信息的时候,则需要通过ajax不挺的刷新数据,或者使用长连接(是对ajax的改进,客户端和服务器端建立连接后,一直保持通信,如果服务器一直没有新消息则一直保持通信,知道服务端有消息返回客户端,然后关闭连接)

不管是ajax轮询还是长连接都是:客户端主动发起请求,服务端被动接收,服务端不能主动发起;怎么才能可以由服务端主动发起将数据给客户端?那么就得使用websocket协议进行通讯。 websocket协议的优缺点

1、减少请求费时费资源

http请求需要客户端发起情况后客户端再回应,websocket服务端可以直接发起请求,减少不必要的网络请求时间损耗和网络流量

2:、更持久

http请求是无状态的,请求响应完就断开了连接,websocket经过一次握手后就一直保持连接,直到主动关闭连接

3、更主动

http服务端无法主动发起请求客户端,websocket建立连接后可以主动给客户端发消息

四、websocket协议解析

websocket协议首先需要借助http或https协议来完成握手动作,握手完成后,才会通过websocket协议进行交互

封装websocket

import { Message } from 'element-ui'

export const connectSocket = () => {

    let lockReconnect = false; //避免重复连接

    //判断当前浏览器是否支持WebSocket

    function createWebSocket() {

        try {

            if ('WebSocket' in window) {

                let protocol = window.location.protocol;

                if (protocol === 'http:') {

                    window.webSocket = new WebSocket("ws://" + window.location.host + "/XXX/XXX/XXX/");

                } else if (protocol === 'https:') {

                    window.webSocket = new WebSocket("wss://" + window.location.host + "/XXX/XXX/XXX/");

                }

                websocketInit()

            } else {

                Message.error('你的浏览器不支持websocket,请切换浏览器。');

            }



        } catch (e) {

            websocketReconnect()

        }

    }

    createWebSocket()


    function websocketInit() {

        let timeId = '';

        //连接成功建立的回调方法

        webSocket.onopen = function() {

            console.log("webSocket连接成功");

            timeId = setInterval(() => {

                webSocket.send('ping');

            }, 30000)

        };

        webSocket.onclose = function(e) {

            console.log("webSocket连接关闭");

            websocketReconnect()

        };

        //每个页面接收消息的处理方式都不同

        // webSocket.onmessage = function () {

        //     //   Notification({

        //     //     dangerouslyUseHTMLString: true,

        //     //     message: '<p>'+event.data+'</p>',

        //     //   })

        //     // heartCheck.start();

        // };

        webSocket.onerror = function() {
            console.log("WebSocket连接发生错误");
        };

        //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。

        window.onbeforeunload = function() {

            webSocket.close();
        }
    }

    function websocketReconnect() {

        if (lockReconnect) { // 是否已经执行重连
            return;
        }

        lockReconnect = true;

        //没连接上会一直重连,设置延迟避免请求过多

        timer && clearTimeout(timer);

        var timer = setTimeout(function() {

            createWebSocket()

            lockReconnect = false;

        }, 3000);
    }

};
在main.Js中挂载

import {connectSocket} from './api/api'

Vue.prototype.connectSocket = connectSocket;

页面使用

 this.connectSocket()

        window.webSocket.onmessage = function (event) {

            console.log(event)

            this.list = event.data

        }

可以在页面中使用

<template>
  <div></div>
</template>

<script>
export default {
  data() {
    return {
      audio: null,
      socket: null,
      timeout: 30 * 1000,
      heartBeatTimer: null,
      reconnectTimer: null,
    };
  },
   mounted() {
    this.initWebSocket();
  },
  methods: {
    initWebSocket() {
      this.createWebSocket();
      this.reconnectTimer = window.setInterval(() => {
        if (this.socket.readyState === 3) {
          this.stopHeartBeat();
          this.createWebSocket();
        }
      }, 60000);
    },
    stopHeartBeat() {
      this.heartBeatTimer = setInterval(() => {
        this.socket.send("hello server!");
      }, this.timeout);
    },
    startHeartBeat() {
      clearInterval(this.heartBeatTimer);
      this.heartBeatTimer = null;
    },
    createWebSocket() {
      const host = window.location.host;
      this.socket = new WebSocket(`wss://${host}/websocket`);
      this.socket.onopen = this.onopen;
      this.socket.onmessage = this.onmessage;
      this.socket.onclose = this.onclose;
      this.socket.onerror = this.onerror;
    },
    //用于指定连接成功后的回调函数。
    onopen(event) {
      this.startHeartBeat();
    },
    //用于指定当从服务器接受到信息时的回调函数。
    onmessage(event) {
      let self = this;
      let message = JSON.parse(event.data);
      if (message.type == "sessionId") {
        //save sessionId
      } else {
        self.audio.play();
        //做业务处理
      }
    },
    //用于指定连接关闭后的回调函数。
    onclose(event) {
      console.log("成功关闭链接", event);
    },
    //用于指定连接失败后的回调函数。
    onerror(event) {
      console.log("链接出错", event);
    },
  },
  created() {
    this.audio = new Audio(require("./assets/audio/audio.mp3"));
  },
 
  beforeDestroy() {
    this.socket.close();
    clearInterval(this.heartBeatTimer);
    clearInterval(this.reconnectTimer);
    this.heartBeatTimer = null;
    this.reconnectTimer = null;
  },
};
</script>