zoukankan      html  css  js  c++  java
  • 轮询、服务器发送事件与WebSocket

    轮询

    传统轮询

    传统轮询借助setInterval或者setTimeout,并结合Ajax技术的方式实现。

    //1
    //使用setInterval,每隔10s向服务器发送一次请求。
    //存在的问题是:在网络不稳定的情况下,无法保证请求以及服务器响应的顺序。
    setInterval(function() {
        $.getJSON("url-path")
        .done(function(data) {
            console.log(data);
        });
    }, 10000);
    
    //2
    //使用setTimeout,在每一次的请求并收到响应后,发送下一次请求。
    //解决的问题:保证了每次请求的先后顺序。
    //存在的问题:仍然无法保证每次请求的间隔时间。
    function poll() {
        setTimeout(function() {
            $.getJSON("url-path")
            .done(function(data) {
                console.log(data);
                
                //发起下一次请求
                poll();
            });
        }, 1000);
    }
    

    缺点分析

    每次都需要新发起一条http请求。

    客户端来说占用较多内存资源与请求资源,对服务器来说占用较多的内存资源与带宽资源

    补充:对TCP协议三次握手的理解。

    请求(含SYN标记的数据包):客户端-->Apache/nginx服务器-->php/java/...等后端程序
    响应(含SYN-ACK标记的数据包):后端程序-->Apache/nginx服务器-->客户端
    确认收到(含ACK标记的数据包):客户端-->Apache/nginx服务器-->后端程序
    

    长轮询

    长轮询与下文的服务器发送事件和WebSocket都需要服务器配合。

    //服务器
    //通过死循环,以资源的修改时间作为循环跳出条件。
    //就是上文三次握手的服务器响应阶段,被后端程序的死循环“hold”住。
    //当请求的服务器资源的最后一次修改时间==不旧于==客户端请求参数所携带资源的时间(Last-Modified)时,跳出循环,并返回数据。
    
    //客户端
    function longPoll(_timeStamp) {
        let _timeStamp;
        $.get("url-path")
        .done(function(data) {
            try{
                let res = JSON.parse(data);
                console.log(res.msg);
            }catch(e) {}
        })
        .always(function() {
            setTimeout(function() {
                longPoll(_timeStamp || Date.now() / 1000);
            }, 10000); 
        });
    }
    

    缺点:服务器资源消耗大。

    解决的问题:减少了http请求。

    服务器发送事件(Server-sent Event)

    该方法有几大特征如下。

    1. HTML5规范的组成部分。
    2. 服务器到客户端的单向通信,不需要由客户端发起。
    3. 以“事件流”的格式产生并推送。
      其格式说明如下:
      • MIME类型:text/event-stream
      • event:事件类型
      • data:消息内容
      • id:用于设置客户端EventSource对象的“last event ID string”内部属性
      • retry:指定重新连接的时间

    客户端的处理方式: 借助EventSource对象实现。

    let eventSource = new EventSource("/path/to/server");
    eventSource.onmessage = (e) => {
        console.log(e.event, e.data);
    };
    
    //或者
    eventSource.addEventListener("ping", function(e) {
       console.log(e.event, e.data); 
    });
    

    缺点:所有IE(包括Edge)都不支持该事件,可以通过EventSource Polyfill进行兼容处理(本质上仍然是轮询)。

    WebSocket

    WebSocket有以下特征:

    1. HTML5规范的组成部分,现在的版本是RFC6455。
    2. 实现原理较上文的几种方式不同。
    3. 基于TCP协议。
      • 看到这里,博客和知乎也有说基于HTTP协议的,列出网上的集合以及个人理解的集合图。

    image

    知乎上Ovear的详细解答:WebSocket借用HTTP协议来完成了部分握手操作。

    //HTTP请求发送时,借助以下字段,通知服务器将协议切换到WebSocket。
    Upgrade: websocket
    Connection: Upgrade
    

    image

    个人的理解

    继续列举它的特征
    4. WebSocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
    5. 服务器完成协议升级后,服务端可以主动推送信息给客户端。
    6. 需要socket程序实现以及额外的端口。

    了解特征五之后,再思考一个问题,WebSocket与本文第二项#服务器发送事件有什么区别,与长轮询呢?

    先来看一下Websocket与长轮询的区别。

    WebSocket的流程

    请求(第一次握手,同时将协议升级到WebSocket):客户端-->Apache/nginx服务器-->后端处理程序
    等待1(后端处理程序未通知信息):Apache/nginx服务器-->客户端(保持连接状态,使得服务器一直能够了解客户端的信息?)
    等待2(后端处理程序通知信息):后端处理程序-->Apache/nginx服务器-->客户端(通知客户端更新数据)
    

    长轮询的流程

    请求(含SYN标记的数据包):客户端-->Apache/nginx服务器-->后端处理程序
    响应(含SYN-ACK标记的数据包):后端程序“hold”住请求,待资源更新后才响应-->Apache/nginx服务器-->客户端
    确认收到(含ACK标记的数据包):客户端-->Apache/nginx服务器-->后端程序
    ...重复N次
    

    显而易见的是,WebSocket协议免去了几个重复的流程。有以下几个优点:

    1. 不需要反复发送和确认http请求,免去服务器对http请求反复解析的工作。
    2. 资源未更新时,不需要通过后端代码拖延响应的时机。WebSocket把与客户端保持通信的任务交给了服务器,因此减少了本身处理速度就慢的程序的压力。

    与服务器发送事件的区别待补充

    简单WebSocket服务器实现代码如下。
    服务器(Node.js)

    var WebSocketServer = require('ws').Server;
    var wss = new WebSocketServer({ port: 8080 });
    
    wss.on("connection", function(socket) {
        socket.on("message", function(ms) {
           console.log(msg); 
           socket.send("Nice to meet you!");
        });
    });
    

    浏览器作为客户端

    //WebSocket为客户端JavaScript的原生对象
    var ws = new WebSocket("ws://localhost:8080");
    ws.onopen = function(event) {
        ws.send("Hello there");
    }
    ws.onmessage = function(event) {
        console.log(event.data);
    }
    

    本文是根据参考网址学习所得的笔记和心得。

  • 相关阅读:
    交互设计实用指南系列(10)—别让我思考
    交互设计实用指南系列11-减少记忆负担
    交互设计实用指南系列(12)—避免出错
    复杂产品的响应式设计【流程篇】
    JS/jQuery判断DOM节点是否存在
    jquery.validate手册 (5)
    jquery.validate手册 (4)
    jquery.validate手册 (3)
    jquery.validate手册 (2)
    Java零基础学习(二)自定义类型及基本语法
  • 原文地址:https://www.cnblogs.com/foxNike/p/6373939.html
Copyright © 2011-2022 走看看