zoukankan      html  css  js  c++  java
  • 关于comet

    Comet是彗星的意思,这一技术之所以借用这个名字,是因为这里的每一次请求都有一个长长的“尾巴”。这个长尾巴就是我们感兴趣的长连接。

    因为长连接的实现,Comet可以不需要安装浏览器插件就可以向客户端“服务推送”。这一重要特性,可以用于许多场合,譬如监控、即时通信、即时报价系统等应用,该技术使得这些服务器可以将新的变化实时传送到客户端,而无须客户端不停地刷新、发送请求。

    Comet实现的主要方式有:基于 AJAX 的长轮询方式;基于 iframe 及 htmlfile 的流方式。

    下面是Javascript作为客户端,PHP为服务器端的一个示例代码。参考了这里:http://blog.leezhong.com/tech/2011/03/21/php-comet.html

    用Javascript写的客户端:

    <html>
        <head>
            <meta http-equivv="Content-Type" content="text/html: charset=utf-8">
            <title> Comet Test </title>
        </head>
        <body>
            <p><a class='customAlert' href="#">publish customAlert</a></p>
            <p><a class='customAlert2' href="#">publish customAlert2</a></p>
            <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
            <script type="text/javascript" src="NovComet.js"></script>
            <script type="text/javascript"> 
                    NovComet.subscribe('customAlert', function(data) {
                        //console.log('customAlert');
                        alert('customAlert published!');
                    });
                    NovComet.subscribe('customAlert2', function(data) {
                        //console.log('customAlert2');
                        alert('customAlert2 published!');
                    });
                    
                    $(document).ready( function() {
                        $("a.customAlert").click(function(event) {
                            NovComet.publish('customAlert');
                        });
                        
                        $("a.customAlert2").click(function(event) {
                            NovComet.publish('customAlert2');
                        })
                        
                        NovComet.run();
                    });
            </script>
        </body>
    </html>           

    1、上面alert('customAlert2 published!')是吧customAlert的弹出到屏幕。

    2、$("a.customAlert*").click(function{})是jQuery的调用,两个监听事件,当有click时,执行函数function()。

    3、然后就是NovComet.run()了。

    下面是NovComet的实现:

    //NovComet.js
    NovComet={
        sleepTime: 800,
        _subscribed: {},
        _timeout: undefined,
        _baseurl: "comet.php",
        _args: '',
        _urlParam: 'subscribed',
        
        subscribe: function(id, callback) {
            NovComet._subscribed[id] = {
                cbk: callback,
                timestmp: NovComet._getCurrentTimestamp(),
            };
            return NovComet;
        },
        
        _refresh: function() {
            NovComet._timeout = setTimeout(function() {
                NovComet.run()
            }, NovComet.sleepTime);
        },
        
        init: function(baseurl) {
            if (baseurl != undefined) {
                NovComet._baseurl = baseurl;
            }
        },
        
        _getCurrentTimestamp: function() {
            return Math.round(new Date().getTime() / 1000);
        },
        
        run: function() {
            var cometCheckUrl = NovComet._baseurl + '?' + NovComet._args;
            for (var id in NovComet._subscribed) {
                var currentTimestamp = NovComet._subscribed[id]['timestmp'];
                
                cometCheckUrl += '&' + NovComet._urlParam+ '[' + id + ']=' +
                    currentTimestamp;
            }
            cometCheckUrl += '&' + NovComet._getCurrentTimestamp();
            
            $.getJSON(cometCheckUrl, function(data) {
                switch(data.s) {
                    case 0: //sin cambios
                        NovComet._refresh();
                        break;
                    case 1: //trigger
                        for (var id in data['k']) {
                            NovComet._subscribed[id]['timestmp'] = data['k'][id];
                            NovComet._subscribed[id].cbk(data.k);
                        }
                        NovComet._refresh();
                        break;
                }
            } );
        },
        
        publish: function(id) {
            var cometPublishUrl = NovComet._baseurl + '?' + NovComet._args;
            cometPublishUrl += '&publish=' + id;
            $.getJSON(cometPublishUrl);
        }
    };

    1、run里面,这里把所有的请求内容给串了一串,比如subscribed[customAlert]=1300016814&subscribed[customAlert2]=1300016814&1300016825,这样php收到后,就会得到$_GET[subscribed]数组,最后那个时间戳是为了避免请求被缓存。

    2、run里面,检测到收到的JSON格式data的s值为0,它会去检查一下是否是超时,没的话什么都不做;如果data.s的值为1,说明已经有事件被提交,判断后则调用对应的callback来展示,在这里,则是调用上面的alert,弹出相应的提示框。

    3、publish方法执行后,会构造一个类似: ?publish=customAlert 这样一个url发送到后台。后台检测到pubish参数,则获取该参数的值,并更新对应文件的mtime。

    用PHP实现服务器端:

    <?php
    
    // comet.php
    include('NovComet.php');
    $comet = new NovComet();
    
    $publish = filter_input(INPUT_GET, 'publish', FILTER_SANITIZE_STRING);
    if ($publish != '') {
        echo $comet->publish($publish);
    } else if (filter_has_var(INPUT_GET, 'subscribed')){
        foreach ($_GET['subscribed'] as $key => $value) {
            $comet->setVar($key, $value);
        }
        echo $comet->run();
    }
    ?>

    如果收到publish,则调用$comet->publish来处理,并把处理结果打印出来;否则如果输入里携带有subscribed信息,则取出该arrary,并执行$Comet->run。

    至于run做了什么,具体看下面:

    <?php
    // NovComet.php
    
    class NovComet {
        const COMET_OK = 0;
        const COMET_CHANGED = 1;
        
        private $_tries;
        private $_var;
        private $_sleep;
        private $_ids = array();
        private $_callback = null;
        
        public function __construct($tries = 20, $sleep = 30) {
            $this->_tries = $tries;
            $this->_sleep = $sleep;
        }
        
        public function setVar($key, $value) {
            $this->_var[$key] = $value;
        }
        
        public function setTries($tries) {
            $this->_tries = $tries;
        }
        
        public function setSleepTime($sleep) {
            $this->_sleep = $sleep;
        }
        
        public function setCallbackCheck($callback) {
            $this->_callback = $callback;
        }
        
        const DEFAULT_COMET_PATH = "./%s.comet";
        
        public function run() {
            if (is_null($this->_callback)) {
                $defaultCometPath = self::DEFAULT_COMET_PATH;
                $callback = function($id) use ($defaultCometPath) {
                    $cometFile = sprintf($defaultCometPath, $id);
                    return (is_file($cometFile) ? filemtime($cometFile) : 0);
                };
            } else {
                $callback = $this->_callback;
            }
            
            for ($i = 0; $i < $this->_tries; $i++) {
                foreach ($this->_var as $id => $timestamp) {
                    if ((integer) $timestamp == 0) {
                        $timestamp = time();
                    }
                    
                    $fileTimestamp = $callback($id);
                    
                    if ($fileTimestamp > $timestamp) {
                        $out[$id] = $fileTimestamp;
                    }
                    
                    clearstatcache();
                }
                if (count($out) > 0) {
                    return json_encode(array('s' => self::COMET_CHANGED, 'k' => $out));
                }
                sleep($this->_sleep);
            }
            return json_encode(array('s' => self::COMET_OK));
        }
        
        public function publish($id) {
            return json_encode(touch(sprintf(self::DEFAULT_COMET_PATH, $id)));
        }
    }           
    ?>

    注意,这里使用了PHP5.3以后的新特性闭包(closure),所以,如果PHP是5.2或更早版本,会报错:

    Parse error: syntax error, unexpected T_FUNCTION in

    遇到这个问题,可以单独实现callback解决。

    所以,整体上来讲,服务器端:

    1、收到publish时,创建了一个以id为名的文件;如果文件存在,就更新它的修改时间。

    2、run时,如果发现该$id文件存在,且时间戳大于之前保存的该$id对应的时间戳(通过setVar设置的),说明$id事件被触发,处理完后把$id放到$out数组中。

    3、如果Comet发现out队列非空,则发送JSON {s=COMET_CHANGED,k=$id}。

    4、如果已经运行了(tries x sleep)时长,还没有收到publish,则发送JSON {s=COMET_OK}表示Comet已经结束。

  • 相关阅读:
    智能手机
    Micro LED
    paper-10-IRM-in-MANETs
    INFOCOM
    如何基于 Android Things 构建一个智能家居系统?
    (OK) VNCserver
    CCF 2016-04-2 俄罗斯方块
    CCF 2016-04-1 折点计数
    洛谷 P1927 防护伞
    洛谷 P1843 奶牛晒衣服
  • 原文地址:https://www.cnblogs.com/pied/p/3593619.html
Copyright © 2011-2022 走看看