• 数据实时更新--webSocket/轮询


    一. 基本概念

       单工:单向通信。即只能服务器->客户端。例如: UDP协议

    半双工:既可以服务器->客户端,也可以客户端->服务器。但是同一时间,只能是一个方向。例如: http协议。

    全双工:双向通信。同一时间内既可以客户端->服务器;也可以服务器->客户端。例如:webSocket协议

    二. 双向通信

    服务器实时的将更新的数据发送到客户端。
    应用:
    1)即时聊天工具
    2)股票等实时信息展示工具
     
    有以下实现方式

    1. 轮询

    轮询即周期性(setInterval)的发起请求并返回响应(发送请求->响应数据->关闭连接->发送请求)。

    如果响应的所需时间过长,它的再次请求也不会等待上一次的响应完成。

    缺点:

    1)请求过于频繁,请求数过多,每次请求都要携带请求头,浪费流量,消耗CPU的利用率

    2)当客户端过多时,会导致并发数量过高

    3)后台数据不频繁变化时, 频繁发出的很多请求是无效请求

     

    示例:

    客户端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
    </head>
    <body>
      <div id="root"></div>
      <script>
          const xhr = new XMLHttpRequest();
          setInterval(function() {
            xhr.open('GET', '/clock', true);
            xhr.onreadystatechange = function() {
              if(xhr.readyState === 4 && xhr.status === 200) {
                window.root.innerHTML = xhr.response;
              }
            }
            xhr.send();
          }, 1000);
      </script>
    </body>
    </html>

    服务器:

    const express = require('express');
    const app = express();
    app.use(express.static(__dirname));
    app.get('/clock', function(req, res) {
      res.send(new Date().toLocaleString());
    });
    app.listen(8888);

    2. 长轮询(Long Polling)

    长轮询是轮询的优化。它会等待上一次的响应完成后(返回需要的数据)或者请求超时后,再发起下一次的请求。

    优点:

    如果响应时间大于轮询的周期频率,会减少请求次数,实现节约流量(请求header/请求次数),提高CPU利用率的作用。

    示例:

    客户端:

    <body>
      <div id="root"></div>
      <script>
          const xhr = new XMLHttpRequest();
          // 自执行函数
          (function longPolling() {
            xhr.open('GET', '/clock', true);
            xhr.onreadystatechange = function() {
              if(xhr.readyState === 4 && xhr.status === 200) {
                // 等响应返回后再次发起请求
                window.root.innerHTML = xhr.response;
                longPolling();
              }
            }
            xhr.send();
          })();
      </script>
    </body>

    服务器:

    const express = require('express');
    const app = express();
    app.use(express.static(__dirname));
    app.get('/clock', function(req, res) {
      // 模拟响应时间较长的情况
      setTimeout(function() {
        res.send(new Date().toLocaleString());
      }, 3000);
    });
    app.listen(8888);

    3. iframe流

    本质上是使用“长连接”,即请求发送后,定时返回响应,并不调用(res.end)断开连接。

    在页面中嵌套一个隐藏的iframe,其src设置为一个长链接请求,服务器源源不断的向客户端推送数据。

     

    示例:

    客户端

    <body>
      <div id="root"></div>
      <iframe src='/clock' style="display: none"></iframe>
    </body>

    服务器

    const express = require('express');
    const app = express();
    app.use(express.static(__dirname));
    app.get('/clock', function(req, res) {
      setInterval(function() {
        // 定时调用res.write/不调用res.end;即不断开连接
        // 时间必须用双引号包裹,否则不会将其识别为字符串
        res.write(`
          <script>
            parent.document.getElementById('root').innerHTML = "${new Date().toLocaleString()}"
          </script>
        `);
      }, 1000)
    });
    app.listen(8888);

     4. webSocket

    WebSocket是H5提供的一种新的通信方式,可以使客户端和服务器保持持久连接。

    WebSocket使用ws协议,和http协议是同级协议,都是应用层协议。而TCP协议是传输层协议。

    WebSocket基于TCP协议,可以基于TCP实现webSocket服务器。并且复用http协议的握手通道。

    优点:

    1)全双工通信

    2)请求头体积小

    缺点:

    1)不兼容

    2)客户端和浏览器端用法不同

    示例:

    客户端

    <body>
      用户:<input id="username" />
      密码:<input id="password" type="password" />
      <br/>
      <button onclick="login()">登录</button>
      <script>
        const ws = new WebSocket('ws://localhost:8888');
        ws.onopen = function() {
          console.log('连接成功');
        };
        ws.onmessage = function(event) {// 监听响应事件
          console.log('接受到服务器响应',event.data);
        };
        // 登录函数
        function login() {
          const username = document.getElementById('username').value;
          const password = document.getElementById('password').value;
          // 客户端发送登录信息
          ws.send(JSON.stringify({type: 'login', username, password}));
        }
      </script>
    </body>

    服务器

    // 为静态资源文件起服务;http协议
    const express = require('express');
    const app = express();
    app.use(express.static(__dirname));
    app.get('/clock', function(req, res) {
      res.send(new Date().toLocaleString());
    });
    app.listen(8080);
    
    // ws协议;webSocket通信的服务器
    const WebSocketServer = require('ws').Server;
    const { sign } = require('jsonwebtoken');// 使用JWT
    
    const server = new WebSocketServer({port: 8888});
    server.on('connection', function(socket) {
      console.log('连接成功');
      socket.on('message', function(message) {
        console.log('服务器接收到消息:',message);
        const {username, password, type} = JSON.parse(message);
        if(type === 'login') {
          // 同步获取token; sign的参数依次是data,secret,alg,callback(异步获取token)
          const token = sign({username, password}, 'lyra');// 默认Hmac SHA256
          socket.send(JSON.stringify({type: 'logined', token}));
        }
      })
    });

    5. socket.io

    socket.io是一个webSocket库,它包含浏览器端的js和服务器端的nodeJS, 目的是构建在不同浏览器和设备上的、通用的网络实时应用。

    优点:

    1. 易用性:它封装了客户端和服务端

    2. 跨平台

    3. 自适应: 可以根据浏览器自动从webSocket/长轮询/iframe流中选择

    基础用法:

    // 1. 全局广播
    io.emit('message', content);
    // 2. 向除自己之外的所有人广播
    socket.broadcast.emit('message', content);
    // 3.只广播到特定人(socket对应的客户端用户)
    socket.emit('message', content);
    // 或者
    socket.send(content);
  • 相关阅读:
    在SharePoint 2010 中使用REST时提示:未能加载类型System.Data.Services.Providers.IDataServiceUpdateProvider的解决办法
    个人记录:判断用户组是否存在
    计算列收集
    SharePoint 备忘录(一)
    个人收藏学习SHarePoint比较不错的网站
    修改WINDOWS 2008 r2远程桌面账户登录限制
    Sharepoint 2010新体验之一基于Claims的全新验证机制
    基于SharePoint的单点登录的实现
    [转]这么教你一定能懂!用饮水机教你什么是RAID
    SharePoint随笔
  • 原文地址:https://www.cnblogs.com/lyraLee/p/12323770.html
Copyright © 2020-2023  润新知