zoukankan      html  css  js  c++  java
  • comet 长轮询与 node 实现

    介绍

    comet和ajax都是为了解决HTTP请求中存在的一些问题,comet跟ajax不同的地方在于,ajax是主动’拉’服务端的内容,而comet是服务端主动’推’内容给客户端。实现成本及其简单,比起ajax模拟的 间隔一段去查询服务端内容的方式在性能等各方面都要好。

    有关 comet 和 socket 对比的资料见 Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

    优点

    • 实现很简单。
    • 实时性好,消息延迟小。

    缺点

    • 只能允许服务端推送,客户端中途无法再发消息给服务端。不像 websocket,可以双向的发送消息。
    • 很适合小数据传输,但是不适合大数据。服务端数据变更频繁的话,这种机制和定时轮询比起来没有本质的提高。
    • 没有数据到达时,http 连接会停留一段时间,这会造成服务器资源浪费。设有 1000 个人停留在某个客户端页面,等待 server 端的数据更新,那就很有可能服务器这边挂着 1000 个线程,在不停检测数据是否发生变化。

    不管是长轮询还是短轮询,都不太适用于客户端数量太多的情况,每个服务器所能承载的TCP连接数是有上限的,这种轮询很容易把连接数占光。

    而 websocket 无需循环等待(长轮询),CPU和内存资源不以客户端数量衡量,而是以客户端事件数衡量。是三种方式里性能最佳的。

    用途

    • 聊天室
    • 股票

    代码

    前端部分 index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>H5原生的comet长连接</title>
        <style>
            body {
                640px;
                margin:20px 30px;
            }
            #status {
                10px;
                height: 10px;
                border-radius: 50%;
                position: absolute;
                top:15px;
                left: 0;
                margin:10px;
                background: #999;
            }
            #status.working {
                -webkit-animation: flash 1s infinite;
                -webkit-animation-direction: alternate;
            }
            #msg {
                max-height: 300px;
                overflow: auto;
                border-radius: 5px;
                border:1px solid #ccc;
                margin:20px 0;
                padding: 5px 15px;
                background: #eee;
            }
            #msg li {
                margin:5px 20px;
            }
            @-webkit-keyframes  flash {
                from {
                    box-shadow: 0 0 5px green;
                    background: green;
                }
                to {
                    box-shadow: 0 0 12px green;
                    background: green;
                }
             }
        </style>
    </head>
    <body>
        <p>用node.js实现HTML5原生的comet(长连接)</p>
        <div id="status"></div>
        <button id="switch">开启</button>
        <button id="clean">清空</button>
    
        <ol id="msg"></ol>
        <script>
        var Btn = function () {
            this._switch = document.querySelector('#switch');
            this._clean  = document.querySelector('#clean');
            this._msg    = document.querySelector('#msg');
            this._status = document.querySelector('#status');
            this.es = null;
            this.init();
        };
        Btn.prototype.init = function () {
            var that = this;
            var _msg = that._msg;
            that._clean.addEventListener('click', function () {
                _msg.innerHTML = '';
            });
            that._switch.addEventListener('click', function () {
                if(this.innerText === '开启') {
                    that.on();
                } else {
                    that.off();
                }
            });
            that.on();
        };
        Btn.prototype.on = function () {
            var that = this;
            // 1. 声明EventSource
            that.es = new EventSource('/msg');
            // 2. 监听数据
            that.es.onmessage = function (e) {
                document.querySelector('#msg').innerHTML += '<li>'+ e.data +'</li>'
            };
            that._switch.innerText = '关掉';
            that._status.classList.add('working');
        };
        Btn.prototype.off = function () {
            this.es.close();
            this._switch.innerText = '开启';
            this._status.classList.remove('working');
        };
        new Btn();
        </script>
    </body>
    </html>
    

    node 部分,index.js

    var http = require('http');
    var fs = require('fs');
    var url = require('url');
    var port = process.argv[2] || 3000;
    
    
    http.createServer(function (req, res) {
        var pathname = url.parse(req.url).pathname;
        if(pathname === '/msg') {
            // 1. 设定头信息
            res.writeHead(200, {
                'Content-Type': 'text/event-stream',
                'Cache-Control': 'no-cache',
                'Connection': 'keep-alive'
            });
    
            // 2. 输出内容,必须 "data:" 开头 "
    
    " 结尾(代表结束)
            setInterval(function () {
                res.write('data: ' + Date.now() + '
    
    ');
            }, 1000);
        } else if (pathname === '/index.html' || pathname === '/client.html') {
            // 其他请求显示index.html
            fs.readFile('./index.html', function (err, content) {
                res.writeHead(200, {'Content-Type': 'text/html'});
                res.end(content, 'utf-8');
            });
        } else {
            res.end('');
        }
    }).listen(port);
    
    
    console.log('Server running on port ' + port);
    

    启动后访问 localhost:3000/index.html 就可以看到

    node index.js
    

    参考

    Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

    用node.js实现HTML5原生的comet(长连接)

  • 相关阅读:
    [CF1106E] 边界有问题
    UOJ 67 新年的毒瘤
    BZOJ 1093 [ZJOI2007]最大半连通子图
    codeforces round#510
    codeforces round#509
    杂谈
    BZOJ 3007 [SDOI2012]拯救小云公主
    BZOJ 1799
    BZOJ 3329
    BZOJ 3209 花神的数论题
  • 原文地址:https://www.cnblogs.com/everlose/p/12742684.html
Copyright © 2011-2022 走看看