精华内容
下载资源
问答
  • WebSocket实现原理

    2020-10-23 13:50:13
    一、什么是websocket WebSocket是应用层第七层的一个应用层协议,它必须依赖HTTP协议进行一次握手,握手成功后,数据就直接从TCP通道传输,与HTTP无关了。即:websocket分为握手和数据传输阶段,即进行了HTTP、握手+...

    一、什么是websocket
    WebSocket是应用层第七层的一个应用层协议,它必须依赖HTTP协议进行一次握手,握手成功后,数据就直接从TCP通道传输,与HTTP无关了。即:websocket分为握手和数据传输阶段,即进行了HTTP、握手+双工的TCP连接。
    二、vue中使用websocket的正确方法

    <template>
      <div class="test">
    
      </div>
    </template>
    
    <script>
      export default {
        name : 'test',
        data() {
          return {
            websock: null,
          }
        },
        created() {
          this.initWebSocket();
        },
        destroyed() {
          this.websock.close() //离开路由之后断开websocket连接
        },
        methods: {
          initWebSocket(){ //初始化weosocket
            const wsuri = "ws://127.0.0.1:8080";
            this.websock = new WebSocket(wsuri);
            this.websock.onmessage = this.websocketonmessage;
            this.websock.onopen = this.websocketonopen;
            this.websock.onerror = this.websocketonerror;
            this.websock.onclose = this.websocketclose;
          },
          websocketonopen(){ //连接建立之后执行send方法发送数据
            let actions = {"test":"12345"};
            this.websocketsend(JSON.stringify(actions));
          },
          websocketonerror(){//连接建立失败重连
            this.initWebSocket();
          },
          websocketonmessage(e){ //数据接收
            const redata = JSON.parse(e.data);
          },
          websocketsend(Data){//数据发送
            this.websock.send(Data);
          },
          websocketclose(e){  //关闭
            console.log('断开连接',e);
          },
        },
      }
    </script>
    <style lang='less'>
     
    </style>
    
    
    展开全文
  • 文章目录前端实时推送浅析前言短轮询短轮询简介优点缺点适用场景长轮询长轮询简介优点缺点适用场景长连接SSE长连接SSE简介优点缺点适用场景WebSocketWebSocket简介优点缺点适用场景websocket底层原理探究websocket ...

    前端实时推送浅析

    前言

    前段时间,完成了项目组分配的一个任务——数据实时大屏,即把商场销售、车流、客流和人流等数据展示到页面上。本次项目采用的是定时轮询的方式去查询数据,总结一下,存在的问题:十分钟执行的定时任务,有时候定时任务尚未执行完成,这时若有前端查询请求,实际上这是无效的查询请求。当然大屏的用户量较少,定时轮询获取数据并无太大问题,但是如果是百万甚至千万的用户,采用定时轮询问题就来了。所以,我根据已有的经验,总结了一下前端如果及时获取后端数据的方法,记录一下,以便将来针对不同的业务场景可以快速的进行技术选型。下面主要对四种方法进行分析和总结:

    1、短轮询。2、长轮询,3、长连接SSE。4、websocket。并对websocket进行重点分析,如有不当之处,欢迎各位大神进行纠正。

    短轮询

    短轮询简介

    短轮询原理比较简单,客户端按照一定的频率定时向后台服务器发送请求,服务器接收到请求后,进行响应返回数据给客户端,通常采取setInterval实现。

    什么是短轮询?用通俗易懂的话举例解释,小张在看直播的时候,看到一个自己十分心仪的女主播小红,于是小张每十分钟就向女主播发一句问候语:“小姐姐,我要刷个游艇吗”,女主播一接到消息就回复他:“小哥哥,你真帅”,下一次回复他:“小哥哥,可以多发几个游艇吗”。

    在这里插入图片描述

    //短轮询伪代码
    var xhr = new XMLHttpRequest();
    setInterval(function () {
      xhr.open('GET', '/sendGifToZB');
      xhr.onreadystatechange = function () {
      };
      xhr.send();
    }, 60000)
    

    优点

    短轮询的优点:

    • 技术简单,易于理解。
    • 易于维护,前端升级改造维护等不牵涉服务端。
    • 兼容性好,几乎兼容当下所有的主流版本浏览器。

    缺点

    • 资源浪费,不断的建立连接,当定时时间短,客户量多时,会增加服务器的负担。
    • 数据及时性问题,无法感知到客户端数据是否更新,产生很多无效请求。存在需要更新的时候没更新,不需要更新的时候又去请求的情况。

    适用场景

    轮询适用于那些同时在线用户数量比较少,对数据及时性要求不高,并且不特别注重性能或低版本浏览器的B/S应用。

    长轮询

    长轮询简介

    客户端向服务端发起请求,如果服务器没有可以返回的数据,不会立刻返回一个空结果,而是保持这个连接,一直等待数据,一旦有数据,便将数据作为结果返回给客户端。

    什么是长轮询?用通俗易懂的话举例解释,经过了几轮的直播发礼物之后,小红成了小张的女神。小张便给小红发消息:“你现在在干嘛”,小张心里满怀着期待,等啊等,一晚上之后,女神回复他:“昨晚我睡着了”,此刻,小张已经兴奋得无法用言语来形容,马上就说:“你现在在干嘛呀”。又过了一个钟,女神回复他:“我刚吃完早饭”,…

    在这里插入图片描述

    //长轮询伪代码,小张(客户端)向后小红(服务端)轮询消息
    function getMessagesFromNS() {
      $.ajax({
        async: true,//异步
        url: '/getMessagesFromNS',
        type: 'post',
        dataType: 'json',
        data: {
          question: "nv shen,what are you doing now?"
        },
        timeout: 30000,//超时时间设定30秒
        error: function (xhr, textStatus, thrownError) {
          getMessagesFromNS();//发生异常错误后再次发起请求
        },
        success: function (response) {
          if (message != "timeout") {
            //收到消息后置处理
          }
          //继续问女神在干嘛(请求客服端数据)
          getMessagesFromNS();
        }
      });
    }
    

    优点

    • 减少了无效的请求次数,节约了客户端和服务端的资源,尤其是客户端。
    • 技术成本比较低,不比短轮询复杂多少。
    • 兼容性好,几乎兼容当下所有的主流版本浏览器。

    缺点

    • 与短轮询一样,仍然无法解决及时性的问题。
    • 长轮询相对于短轮询,因为存在一个等待数据的过程,所以需要服务器具有更大的并发能力。

    适用场景

    轮询适用于那些同时在线用户数量比较小,对数据及时性要求不高,并且不特别注重性能或低版本浏览器的B/S应用。

    长连接SSE

    长连接SSE简介

    SSE是Server-sent Event的简写,是一种服务器端到客户端的单向消息推送。对应的浏览器端实现 Event Source 的接口被制定为HTML5 的一部分。SSE与长轮询机制类似,客户端向服务器发送一个请求,服务端会一直保持着连接,通过这个连接就可以让消息再次发送,由服务器单向发送给客户端。与长轮询的区别是,长轮询服务端发消息给客户端后,双方的连接就断了,需要客户端重新发起一个连接请求,一次连接接收一次消息。而SSE一次连接可以接收多次消息。

    什么是SSE?用通俗易懂的话举例解释,小张经过不懈的努力,小张终于熬成了恋爱候选对象,小张便对女神小红说:“女神,你那边有什么需求吗,可以尽管提,我一定办到”。女神这时候心里有了一丝丝触动,于是回复小张说:“我要买一部手机”,两天后又跟小张说:“我要去马尔代夫旅游”,…
    在这里插入图片描述

    //客户端
    //创建EventSource 实例
    var source = new EventSource(url)
    // 建立连接后,触发`open` 事件
    source.onopen = (event) => {
      // ...
    }
    // 收到消息,触发`message` 事件
    source.onmessage = (event) => {
      // ...
    }
    // 发生错误,触发`error` 事件
    source.onerror = (event) => {
      // ...
    }
    // 自定义事件
    source.addEventListener('eventName', event => {
      // ...
    }, false)
    source.close()
    
    //服务端
    //SSE的相应,需要设置如下的Http头信息
    
    Content - Type: text / event - stream
    Cache - Control: no - cache
    Connection: keep - alive
    

    优点

    • 解决了短轮询和长轮询中,解决不了的数据及时性问题,实现了数据流由服务器向客户端的推送。
    • 进一步解决了资源浪费的问题。
    • 技术成本适中,复杂于短轮询长轮询,但简单于websocket。

    缺点

    • 不兼容IE浏览器。
    • 单工通信,连接之后,服务器端向客户端传输数据,客户端不能向客户端传输数据。
    • 同源限制,存在CORS同源限制。

    适用场景

    适用于对数据及时性有要求,服务端向客户端单向推送数据的场景。

    WebSocket

    WebSocket简介

    websocket是html5规范中的一个部分,它借鉴了socket这种思想,为web应用程序客户端和服务端之间提供了一种全双工通信机制。同时,它又是一种新的应用层协议,websocket协议是为了提供web应用程序和服务端全双工通信而专门制定的一种应用层协议,通常它表示为:ws://echo.websocket.org/?encoding=text HTTP/1.1,可以看到除了前面的协议名和http不同之外,它的表示地址就是传统的url地址。Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充,或者说借用了http的握手功能实现初始连接。

    什么是websocket?用通俗易懂的话举例解释,小张经过不懈的努力,终于和小红成为了情侣,从此跟小红过上了幸福的生活,小红对小张也不再不冷不热了,双方都会主动发起聊天对话,小红经常问小张:“我们去吃什么”,“去哪里玩”…小张也会跟小红说:“你在干嘛”,“多喝热水”…

    在这里插入图片描述

    //websocket 客户端伪代码
    var ws = new WebSocket("ws://nvshen:520");
    ws.onopen = function () {
      ws.send("dring more hot water");
    };
    ws.onmessage = function (e) {
      console.log(e.data);
    };
    ws.onclose = function () {
      console.log("closed...");
    };
    ws.onerror = function () {
      console.log(this.readyState);
    }
    

    优点

    • 实现了全双工通信。
    • 节约资源,WebSocket协议一旦建议后,互相沟通所消耗的请求头是很小的。
    • 解决数据及时性问题,双方可以获取最新的消息,进行处理。
    • 支持文本传输,二进制数据传输。
    • 没有同源限制,客户端可以与任意服务器通信。

    缺点

    • 相对于其他三种,技术复杂,需要前后端支持。
    • 兼容性相对较差,部分浏览器不支持。

    适用场景

    适用于对数据有及时性要求,服务端和客户端双工通信的场景,当然,也可以使用websocket进行单向的数据推送。

    websocket底层原理探究

    websocket底层原理可以简要的概括为三个阶段:1、握手阶段。2、数据交换阶段。3、关闭阶段。

    • 握手环节
    1. 首先客户端浏览器要和服务端建立一个TCP连接,基于 HTTP 协议实现,它借用了 HTTP 协议来完成一部分握手。

    所以,握手阶段WebSocket 首先发起一个 HTTP 请求,在请求头加上 Upgrade 字段,该字段用于改变 HTTP 协议版本或者是换用其他协议,把 Upgrade 的值设为 websocket ,即将它升级为 WebSocket 协议。

    在这里插入图片描述

    Upgrade、Connection、Sec-WebSocket-Key、Sec-WebSocket-Version、Sec-WebSocket-Extension 几个属性是 WebSocket 的核心。

    Upgrade、Connection: websocket属性通知 Apache 、 Nginx 等服务器,此次发起的请求要用 WebSocket 协议,而不是http或其他协议。

    Sec-WebSocket-Key : 用于验证服务器端是否采用WebSocket 协议。由客户端生成并发给服务端,用于证明服务端接收到的是一个可受信的连接握手,可以帮助服务端排除自身接收到的由非 WebSocket 客户端发起的连接,该值是一串随机经过 base64 编码的字符串。

    Sec-WebSocket-Version: 表示客户端所使用的协议版本。

    Sec-WebSocket-Extensions: 表示客户端想要表达的协议级的扩展。

    1. 客户端浏览器会生成一个随机字符串(sec-websocket-key),自己留一份,然后基于http协议将随机字符串放在请求头中发送给服务端。

    2. 服务端收到随机字符串后会和服务端的魔法字符串(magic string)(魔法字符串是全球公认的)做一个拼接生成一个大的字符串,然后再用全球公认的算法(sha1+base64)进行加密,生成一个密文,接着将这个密文返回给客户端浏览器。

    在这里插入图片描述

    服务端通过从客户端请求头中读取 Sec-WebSocket-Key 与一串全局唯一的标识字符串(俗称魔串)“258EAFA5-E914-47DA- 95CA-C5AB0DC85B11”做拼接,生成长度为160位的 SHA-1 字符串,然后进行 base64 编码,作为 Sec-WebSocket-Accept 的值回传给客户端。

    Connection和Upgrade: 与请求头中的作用相同

    Sec-WebSocket-Accept: 表明服务器接受了客户端的请求。

    1. 客户端浏览器收到这个密文之后,会用同样的魔法字符串与自己生成的随机字符串进行拼接,再用和服务端相同的加密算法进行加密也得到有一个密文,然后拿自己的密文与服务端传过来的密文进行比较,如果结果一样,则说明服务端支持websocke协议,如果结果不一样,则说明服务端不支持websocket协议。
    • 数据交换阶段

      Websocket 的数据传输是以frame 形式传输的,我们先看一下frame的数据结构:

    在这里插入图片描述

    按照RFC中的描述:

    FIN: 1 bit
    
    表示这是一个消息的最后的一帧。第一个帧也可能是最后一个。 
    %x0 : 还有后续帧 
    %x1 : 最后一帧
    
    RSV1、2、3: 1 bit each
    
    除非一个扩展经过协商赋予了非零值以某种含义,否则必须为0。
    如果没有定义非零值,并且收到了非零的RSV,则websocket链接会失败。
    
    Opcode: 4 bit
    
    解释说明 “Payload data” 的用途/功能
    如果收到了未知的opcode,最后会断开链接
    定义了以下几个opcode值:
        %x0 : 代表连续的帧
        %x1 : text帧
        %x2 : binary帧
        %x3-7 : 为非控制帧而预留的
        %x8 : 关闭握手帧
        %x9 : ping帧
        %xA :  pong帧
        %xB-F : 为非控制帧而预留的
    
    Mask: 1 bit
    
    定义“payload data”是否被添加掩码,
    如果置1, “Masking-key”就会被赋值,
    所有从客户端发往服务器的帧都会被置1。
    
    Payload length: 7 bit | 7+16 bit | 7+64 bit
    
    “payload data” 的长度如果在0~125 bytes范围内,它就是“payload length”,
    如果是126 bytes, 紧随其后的被表示为16 bits的2 bytes无符号整型就是“payload length”,
    如果是127 bytes, 紧随其后的被表示为64 bits的8 bytes无符号整型就是“payload length”。
    
    Masking-key: 0 or 4 bytes
    
    所有从客户端发送到服务器的帧都包含一个32 bits的掩码(如果“mask bit”被设置成1),否则为0 bit。一旦掩码被设置,所有接收到的payload data都必须与该值以一种算法做异或运算来获取真实值。
    
    Payload data: (x+y) bytes
    
    它是"Extension data"和"Application data"的总和,一般扩展数据为空。
    
    Extension data: x bytes
    
    除非扩展被定义,否则就是0。
    任何扩展必须指定其Extension data的长度。
    
    Application data: y bytes
    
    占据"Extension data"之后的剩余帧的空间。
    

    客户端浏览器向服务端发送消息,但是发过来的数据是在浏览器内部进行加密过的密文,服务端收到密文后,会进行解密。主要步骤如下:

    • 去掉头数据取得真实数据:拿到密文第二个字节的后7位,后7位成为pyload_lenth,如果pyload_lenth是127,数据要往后读8个字节,也就是说前面10个字节都是数据头,后面是真正的数据,如果pyload_lenth是126,数据要往后读两个字节,也就是前面4个字节是数据包的头,后面是真正的数据,如果pyload_lenth <= 125的话,不用换往后读了,前面连个字节就是数据头,后面是真正的数据。
    • 对真实进行解密:无论pyload_lenth是127,是126,还是<=125,去掉数据头之后,对数据进一步解密,解密的过程就是再往后读4个字节,这4个字节就是masking-key ,就是掩码,后面就是数据,让masking-key的每个字节与4求余的结果和数据的每个字节进行位运算,就是与或运算,最终位运算运算完了,便得到真正的数据。

    Websocket 的数据以frame数据格式,按照先后顺序传输出去。这样做的好处:

    1. 大数据的传输可以分片传输,避免长度标志位不足够的情况。

    2. 生成数据边传递消息,传输效率得到了极大的提高。

    • 关闭阶段

      • 正常的连接关闭流程
      1. 发送关闭连接请求(Close Handshake)
        即发送Close Frame(Opcode为0x8)。一旦一端发送/接收了一个Close Frame,就开始了Close Handshake,并且连接状态变为Closing。
        Close Frame中如果包含Payload data,则data的前2字节必须为两字节的无符号整形,(同样遵循网络字节序:BE)用于表示状态码,如果2byte之后仍有内容,则应包含utf-8编码的关闭理由。
        如果一端在之前未发送过Close Frame,则当他收到一个Close Frame时,必须回复一个Close Frame。但如果它正在发送数据,则可以推迟到当前数据发送完,再发送Close Frame。比如Close Frame在分片发送时到达,则要等到所有剩余分片发送完之后,才可以作出回复。
      2. 关闭WebSocket连接
        当一端已经收到Close Frame,并已发送了Close Frame时,就可以关闭连接了,close handshake过程结束。这时丢弃所有已经接收到的末尾字节。
      3. 关闭TCP连接
        当底层TCP连接关闭时,连接状态变为Closed。
      • 彻底关闭

      如果TCP连接在Close handshake完成之后关闭,就表示WebSocket连接已经彻底关闭了。如果WebSocket连接并未成功建立,状态也为连接已关闭,但并不是彻底关闭。

      • 正常关闭

      正常关闭过程属于clean close,应当包含close handshake。

      通常来讲,应该由服务器关闭底层TCP连接,而客户端应该等待服务器关闭连接,除非等待超时的话,那么自己关闭底层TCP连接。

      服务器可以随时关闭WebSocket连接,而客户端不可以主动断开连接。

      • 异常关闭
      1. 由于某种算法或规定,一端直接关闭连接。(特指在open handshake(打开连接)阶段)
      2. 底层连接丢失导致的连接中断。
      • 连接失败

      由于某种算法或规范要求指定连接失败。这时,客户端和服务器必须关闭WebSocket连接。当一端得知连接失败时,不准再处理数据,包括响应close frame。

    websocket 心跳检测和重连实现与封装

    websocket 在使用过程中,最担心的问题就是:如果遭遇网络问题等,这个时候服务端没有触发onclose事件,这样会产生多余的连接,并且服务端会继续发送消息给客户端,造成数据丢失。需要一种机制来检测客户端和服务端是否处于正常连接的状态,因此,心跳检测和重连机制就产生了。

    实现思路:

    1、定时器,每隔一段指定的时间,向服务器发送一个数据,服务器收到数据后再发送给客户端,如果客户端通过onmessage事件能监听到服务器返回的数据,那么请求正常。
    2、如果指定时间内,客户端没有收到服务器端返回的响应消息,判定连接断开,使用websocket.close关闭连接。
    3、关闭连接的动作可以通过onclose事件监听到,因此在 onclose 事件内,我们可以调用reconnect事件进行重连。

    以下对心跳检测和重连进行了封装:

    /**
     * websocket心跳检测和重连封装
     *
     * @Author:Fannie
     * @Date:2021年7月25日
     */
    class Heart {
      //心跳计时器
      heartTimeout = 0;
      //心跳计时器
      serverHeartTimeout = 0;
      //间隔时间
      timeout: number;
      /**
       *构造方法
       */
      constructor() {
        //设置间隔时间5s
        this.timeout = 5000;
      }
      //重置
      reset() {
        clearTimeout(this.heartTimeout);
        clearTimeout(this.serverHeartTimeout);
        return this;
      }
      //启动心跳
      start(cb: CallableFunction): void {
        this.heartTimeout = setTimeout(() => {
          cb();
          this.serverHeartTimeout = setTimeout(() => {
            cb();
            //重新开始检测
            this.reset().start(cb());
          }, this.timeout);
        }, this.timeout);
      }
    }
    //配置参数
    interface options {
      url: string;
      hearTime?: number;//心跳时间间隔
      heartMsg?: string;//心跳信息
      isReconnect?: boolean;//是否自动重连
      isRestory?: boolean;//是否销毁
      reconnectTime?: number;//重连时间间隔
      reconnectCount?: number;//重连次数 -1 则不限制
      openCb?: CallableFunction;//连接成功的回调
      closeCb?: CallableFunction;//关闭的回调
      messageCb?: CallableFunction;//消息的回调
      errorCb?: CallableFunction;//错误的回调
    }
     /**
       * 编写Socket,继承Heart
       *
       **/
    class Socket extends Heart {
      ws!: WebSocket;
      reConnecTimer!: number;//重连计时器
      // reConnecCount = 10;//变量保存,防止丢失
      options: options = {
        url: "",
        hearTime: 0,
        heartMsg: "ping",//心跳信息
        isReconnect: true,//是否自动重连
        isRestory: false,//是否销毁
        reconnectTime: 5000,//重连时间间隔
        reconnectCount: -1,//重连次数 -1 则不限制
        openCb: (event: Event) => { console.log("连接成功" + event) },
        closeCb: (event: Event) => { console.log("连接关闭" + event) },
        messageCb: (data: string) => { console.log("接收消息为:" + data) },
        errorCb: (event: Event) => { console.log("错误信息" + event) }
      };
      constructor(ops: options) {
        super();
        this.create();
      }
      //建立连接
      create() {
         //浏览器兼容性判读
        if (!("WebSocket" in window)) {
          new Error("当前浏览器不支持,无法使用");
          return;
        }
          //服务端地址判断
        if (!this.options.url) {
          new Error("地址不存在,无法建立通道");
          return;
        }
          //websocket四部曲
        this.ws = new WebSocket(this.options.url);
        this.onopen();
        this.onclose()
        this.onmessage()
      }
      /**
       * 自定义连接成功事件
       * 如果callback存在,调用callback,不存在调用options中的回调
       * @param callback 回调函数
       */
      onopen(callback?: CallableFunction) {
    
        this.ws.onopen = (event) => {
          clearTimeout(this.reConnecTimer);//清除重连定时器
          // this.options.reconnectCount = this.reConnecCount;//计数器重置
          //建立心跳机制
          super.reset().start(() => {
            this.send(this.options.heartMsg as string);
          });
          if (typeof callback === "function") {
            callback(event)
          } else {
            (typeof this.options.openCb === "function") && this.options.openCb(event)
          }
    
        }
      }
      /**
       * 自定义关闭事件
       * 如果callback存在,调用callback,不存在调用options中的回调
       * @param callback  回调函数
       */
      onclose(callback?: CallableFunction) {
    
        this.ws.onclose = (event) => {
          super.reset();
          !this.options.isRestory && this.onreconnect()
          if (typeof callback === "function") {
            callback(event);
          } else {
            (typeof this.options.closeCb === "function") && this.options.closeCb(event)
          }
        }
      }
      /**
       * 自定义错误事件
       * 如果callback存在,调用callback,不存在调用options中的回调
       * @param callback 回调函数
       */
      onerror(callback?: CallableFunction) {
    
        this.ws.onerror = (event) => {
          if (typeof callback === "function") {
            callback(event)
          } else {
            (typeof this.options.errorCb === "function") && this.options.errorCb(event)
          }
        }
      }
      /**
       * 自定义消息监听事件
       * 如果callback存在,调用callback,不存在调用options中的回调
       * @param callback 回调函数
       */
      onmessage(callback?: CallableFunction) {
    
        this.ws.onmessage = (event) => {
          //收到任何消息,重新开始倒计时心跳检测
          super.reset().start(() => {
            this.send(this.options.heartMsg as string);
          })
          if (typeof callback === "function") {
            callback(event.data)
          } else {
            (typeof this.options.messageCb === "function") && this.options.messageCb(event.data)
          }
        }
      }
      /**
       * 自定义发送消息
       * @param data 发送的信息 
       */
      send(data: string) {
    
        if (this.ws.readyState !== this.ws.OPEN) {
          new Error("没有连接到服务器,无法推送信息");
          return;
        }
        this.ws.send(data);
      }
      /**
       * 连接事件
       */
      onreconnect() {
    
        if (this.options.reconnectCount as number > 0 || this.options.reconnectCount === -1) {
          this.options.reconnectTime = setTimeout(() => {
            this.create();
            if (this.options.reconnectCount !== -1) {
              (this.options.reconnectCount as number)--;
            }
          }, this.options.reconnectTime);
        } else {
          clearTimeout(this.options.reconnectTime);
          // this.options.reconnectCount = this.reConnecCount;
        }
      }
      /**
       * 销毁
       */
      destroy() {
        super.reset();
        clearTimeout(this.reConnecTimer);//清除重连定时器
        this.options.isRestory = true;
        this.ws.close();
      }
    
    }
    //-----------------------------------示例-------------------------------
    let options: options = {
      url: "ws://127.0.0.1:520",//需要服务端启动了该服务
      hearTime: 0,
      heartMsg: "ping",//心跳信息
      isReconnect: true,//是否自动重连
      isRestory: false,//是否销毁
      reconnectTime: 1000,//重连时间间隔
      reconnectCount: -1,//重连次数 -1 则不限制
      openCb: (event: Event) => { console.log("连接成功" + event) },
      closeCb: (event: Event) => { console.log("连接关闭" + event) },
      messageCb: (data: string) => { console.log("接收消息为:" + data) },
      errorCb: (event: Event) => { console.log("错误信息" + event) }
    };
    let ws = new Socket(options)
    

    参考文章

    深入剖析WebSocket的原理

    总结

    通过此次的微博总结,加深了自己对前端数据推送各个技术的理解与记忆。时代是在进步的,技术也是如此,不断的呈现问题,解决问题,不断进化。作为一名程序员,也应该保持着与时俱进的能力,应对新时代的技术潮流,不断完善自己的能力,弥补自己的不足。让自己更强大,在工作中更有用武之地。

    展开全文
  • WebSocket实现原理

    2019-10-11 15:43:12
    首先,浏览器用wss://xxx创建WebSocket连接时,会先通过HTTPS创建安全的连接,然后,该HTTPS连接升级为WebSocket连接,底层通信走的仍然是安全的SSL/TLS协议。 WebSocket支持的浏览器 Chrome Firefox IE >= 10 ...

    概述 

           传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应 用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。

           轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。

        Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。

    Http长连接与Websocket区别

           HTTP1.1通过使用Connection:keep-alive进行长连接,HTTP 1.1默认进行持久连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。这种长连接是一种“伪链接”

           websocket的长连接,是一个真的全双工。长连接第一次tcp链路建立之后,后续数据可以双方都进行发送,不需要发送请求头。

           keep-alive双方并没有建立正真的连接会话,服务端可以在任何一次请求完成后关闭。WebSocket 它本身就规定了是正真的、双工的长连接,两边都必须要维持住连接的状态。

     

    WebSocket流程

            Websocket是html5提出的一个协议规范,是为解决客户端与服务端实时通信。本质上是一个基于tcp,先通过HTTP/HTTPS协议发起一条特殊的http请求进行握手后创建一个用于交换数据的TCP连接。WebSocket优势: 浏览器和服务器只需要要做一个握手的动作,在建立连接之后,双方可以在任意时刻,相互推送信息。同时,服务器与客户端之间交换的头信息很小。

    首先,WebSocket连接必须由浏览器发起,因为请求协议是一个标准的HTTP请求,格式如下:

    GET ws://localhost:3000/ws/chat HTTP/1.1
    Host: localhost
    Upgrade: websocket
    Connection: Upgrade
    Origin: http://localhost:3000
    Sec-WebSocket-Key: client-random-string
    Sec-WebSocket-Version: 13

    该请求和普通的HTTP请求有几点不同:

    GET请求的地址不是类似/path/,而是以ws://开头的地址;
    请求头Upgrade: websocket和Connection: Upgrade表示这个连接将要被转换为WebSocket连接;
    Sec-WebSocket-Key是用于标识这个连接,并非用于加密数据;
    Sec-WebSocket-Version指定了WebSocket的协议版本。

     

    随后,服务器如果接受该请求,就会返回如下响应:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: server-random-string

    该响应代码101表示本次连接的HTTP协议即将被更改,更改后的协议就是Upgrade: websocket指定的WebSocket协议。

    版本号和子协议规定了双方能理解的数据格式,以及是否支持压缩等等。如果仅使用WebSocket的API,就不需要关心这些。

    现在,一个WebSocket连接就建立成功,浏览器和服务器就可以随时主动发送消息给对方。消息有两种,一种是文本,一种是二进制数据。通常,我们可以发送JSON格式的文本,这样,在浏览器处理起来就十分容易。

    为什么WebSocket连接可以实现全双工通信而HTTP连接不行呢?实际上HTTP协议是建立在TCP协议之上的,TCP协议本身就实现了全双工通信,但是HTTP协议的请求-应答机制限制了全双工通信。WebSocket连接建立以后,其实只是简单规定了一下:接下来,咱们通信就不使用HTTP协议了,直接互相发数据吧。

    安全的WebSocket连接机制和HTTPS类似。首先,浏览器用wss://xxx创建WebSocket连接时,会先通过HTTPS创建安全的连接,然后,该HTTPS连接升级为WebSocket连接,底层通信走的仍然是安全的SSL/TLS协议。

     

    WebSocket支持的浏览器

    • Chrome
    • Firefox
    • IE >= 10
    • Sarafi >= 6
    • Android >= 4.4
    • iOS >= 8

     

    Springboot的WebSocket实现

    springboot已经整合了websocket,直接引入包就可以了.实在没什么写的.

    		<dependency>  
               <groupId>org.springframework.boot</groupId>  
               <artifactId>spring-boot-starter-websocket</artifactId>  
           </dependency> 
    

     

     

     

    展开全文
  • WebSocket实现原理

    2020-01-09 01:33:55
    websocket实现原理 1)握手环节:验证服务端是否支持websocket协议 a)创建连接,浏览器连接服务端,创建连接成功 b)浏览器生成一个随机字符串,浏览器存一份该随机字符串,同时发一份给服务端(基于http协议发到...

    1. websocket简介

      websocket同http和https一样,属于tcp基础上的应用层的协议;因此其必然也是存在三次握手四次挥手的过程

      一般来说,我们使用的http协议只能由客户端发起请求,而服务端无法直接主动进行数据推送,这就导致了如果服务端有持续的变化(如聊天室)而客户端获取起来较为复杂(如实时性和服务端压力等)。因此,websocket协议便应运而生
      对于websocket协议来说,客户端和服务端都可以主动推送消息,其中消息内容可以时文本也可以是二进制数据。而且没有同源策略的限制,也不存在跨域问题

      websocket协议的表示符号时ws(ws://xxxx.com);像https一样,如果加密的话,标识符就是wxs

    2. websocket实现原理

    2.1 websocket协议数据收发的过程大概为三个过程:

      1)TCP协议的三次握手四次挥手的过程必然存在
      2)websocket协议本身的握手环节
      3)websocket协议握手成功之后的收发数据环节

    2.2 websocket数据收发过程及原理

    1) websocket握手环节

    握手环节:验证服务端是否支持websocket协议
    		1)创建连接,浏览器连接服务端,创建连接成功
    		2)浏览器生成一个随机字符串,浏览器存一份该随机字符串,同时发一份给服务端(基于http协议发到服务端,会把该字符串放在http请求头里发给服务端)
    		3)服务端收到随机字符串之后,让它跟魔法字符串(magic string,全球公认的固定字符串)拼接,然后再通过sha1算法进行加密然后再通过base64编码后,生成密文
    		4)服务端将密文返回给浏览器(该密文无法反解)
    		5)浏览器也将本地存的随机字符串与magic string进行拼接并加密编码之后得到一个密文
    		6)浏览器将服务端发来的密文与本地的密文进行对比、校验,若通过,则说明两端用的同一个magic string,即用的同一种加密手段,即可以判定服务端支持websocket协议,握手成功;若校验不通过,则代表服务端不支持websocket协议,握手失败
    

    握手成功后,进行收发数据

    2) websocket收发数据环节

    收发数据环节:数据是加密的
    	1)浏览器将数据加密发往客户端
    	2)服务端接收到数据之后进行的解密(解密是全球公认的)
    		a) 拿到第2个字节(8位),取其后7位(即前两个字节的10-16位),也就是数据的前9位都不要,我们取到的7位称之为payload length(7位最大值是127);
    		b) 服务端对payload length的值进行判断:
    			1> 若payload length =  127:
    				  再往后读8个字节(即64bit/位),也就是说前10个字节(8+2)是数据头,后面才是数据
    			2> 若payload length =  126:
    				  再往后读2个字节(即16bit/位),也就是说前4个字节(2+2)是数据头,后面才是数据部分
    			3> 若payload length <= 125:
    				  不往后读,前面2个字节就是数据头,后面都是数据部分
    	3)通过b解密过程获取数据,但是该数据也不是明文的,还需要再解密
    		a) 获取到数据部分后,再往后读4个字节,该4个字节称之为masking key,剩下部分是真正的数据;
    		b) 让masking key与数据的每一个字节进行位运算(与或运算),运算完之后就获取到了最终的数据(具体过程可见官网)
    
    展开全文
  • js实现webSocket客户端的原理

    千次阅读 2020-07-02 19:43:10
    js实现webSocket客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ...
  • 最近再弄soul网关,发现soul网关中的websocket插件路径和项目中的不匹配,重写弄了个websocket插件,顺便把gateway中的websocket看了一下,直接开撸 一、WebsocketRoutingFilter 解析 初始化WebsocketRoutingFilter...
  • WebSocket介绍与原理

    2021-04-10 10:39:37
    WebSocket介绍与原理 WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 ——百度百科 目的:即时通讯,替代轮询 网站上的即时通讯是...
  • websocket地城是不是和http一样用的socket
  • 一、关于WebSocket协议 我们需要弄明白,WebSocket本质上一种计算机网络应用层的协议,用来弥补http协议在持久通信能力上的不足。 我们知道http协议本身是无状态协议,每一个新的http请求,只能通过客户端主动...
  • WebSocket使用及原理

    2018-08-05 16:24:00
    1、WebSocket 1.1、关于WebSocket  WebSocket协议是基于...它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。 1.2、安装依赖模块 # Flask pip3 ...
  • 这里只谈原理就不贴代码了。Android可以参考 JsBridge ,IOS可以参考 WebViewJavascriptBridge 六. 传统的js库能用吗  大部分都不行。官方的解释是 页面的脚本逻辑是在JsCore中运行,JsCore是一个没有窗口...
  • websocket库ws原理分析

    2021-02-05 15:18:45
    ws服务器逻辑由websocket-server.js的WebSocketServer类实现。该类初始化了一些参数后就执行以下代码 if (this._server) { // 给server注册下面事件,返回一个注销函数(用于注销下面注册的事件) this._...
  • 大家都知道Ajax,这是一种借助浏览器端JavaScript实现的异步无刷新请求功能:要客户端按需向服务器发出请求,并异步获取来自服务器的响应,然后按照逻辑更新当前页面的相应内容。但是这仅仅是拉取啊,
  • 首先对于TCP通信来说,每个TCP内核...通过java代码模拟实现, 服务端代码: package cn.com.sjzc.edu.RMI.socketdemo; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class...
  • 微信小程序weapp的底层实现原理

    万次阅读 2016-11-21 12:30:16
    首先声明: 以下所有内容仅是对微信小程序weapp的... wa的运行环境 根据微信官方的说明,wa的运行环境有3个平台,IOS的webkit(苹果开源的浏览器内核),Android的X5(QQ浏览器内核),开发时用的nw.js(C++实现的web
  • WebSocket 是什么原理,为什么可以实现持久连接? 一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) 首先HTTP有1.1和1.0...
  • WebSocket是HTML5出的协议,,也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) ajax 轮询 场景再现:客户端:啦啦啦,有没有新信息(Request) 服务端:没有...
  • java websocket原理及其简易实现

    千次阅读 2017-09-18 10:51:54
    java websocket原理及其简易实现 WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。 WebSocket协议支持(在受控环境中运行不受信任...
  • websocket原理

    2017-12-08 18:15:09
    Websocket是一种在单个TCP连接上进行全双工通讯的协议,双工(duplex)是指两台通讯设备之间,允许有双向的资料传输。在Websocket协议中,客户端和服务端只需要做一个握手的动作,...是一种全双向的通信, 具有底层socke
  • 基于socket包,简易websocket客户端服务端实现,可通过客户端发送消息至服务端,服务端接受消息。 python中socket、socketio、flask-socketio、WebSocket的区别与联系—TCP/IP原理图 socket 是通信的基础,并不是一...
  • 基于socket包,简易websocket客户端服务端实现,可通过客户端发送消息至服务端,服务端接受消息。 python中socket、socketio、flask-socketio、WebSocket的区别与联系---TCP/IP原理图 socket 是通信的基础,并不是...
  • WebSocket原理与基于Spring Boot的实现

    千次阅读 2018-10-21 22:23:16
    总共分成7部分: websocket是什么 它与http的区别 兼容性如何 更高级使用sockjs sockjs的特性 stomp的使用 基于spring的stomp实现
  • WebSocket简介与消息推送 B/S架构的系统多使用HTTP协议,HTTP协议的特点: 1 无状态协议2 用于通过 Internet 发送请求消息和响应消息3 使用端口接收和发送消息,默认为80端口底层通信还是使用Socket完成。 HTTP...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,018
精华内容 2,807
关键字:

websocket底层实现原理