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已经结束。

关于comet的更多相关文章

  1. Comet技术

    1.Comet是什么? 维基百科: Comet是一种用于web的推送技术,能使服务器实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 说白了就是web ...

  2. 基于 Asp.Net的 Comet 技术解析

    Comet技术原理 来自维基百科:Comet是一种用于web的技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 简单的说是一种基于现 ...

  3. Comet ASP.NET AJAX 示例

    最近公司有个项目,里面要求要用到Comet技术,所以就到网上找了一下相关的资料和文章,发现有些人说用Ajax的长轮询比较好,后来就百度了一下,发现comet貌似就是通过ajax演变而来的,也就是com ...

  4. Asp.net MVC Comet推送

    一.简介 在Asp.net MVC实现的Comet推送的原理很简单. 服务器端:接收到服务器发送的AJAX请求,服务器端并不返回,而是将其Hold住,待到有东西要通知客户端时,才将这个请求返回. 客户 ...

  5. 浅入浅出“服务器推送”之一:Comet简介

    最近有个项目,其中有项需求要从服务器端主动向客户端推送数据,本以为很简单,但在实际做的过程中发现很棘手,并没有想象中的简单.从网上搜索学习,发现主流讲的还是Ajax的长轮询技术或者流技术,websoc ...

  6. comet在asp.net中的实现

    网上有关“服务器推送”的介绍非常多,其中一种实现方式就是采用comet技术,在浏览器与服务端之间建立一个http协议的“长连接”,所谓“长连接”,就是指浏览器到服务端的http请求不会马上得到服务端的 ...

  7. 探求网页同步提交、ajax和comet不为人知的秘密(上篇)

    标题里的技术都是web开发里最常见的技术,但是我想这些常用的技术有很多细节是很多朋友不太清楚的,理解这些细节是我们深入掌握这些技术的一把钥匙,今天我就讲讲我使用这些技术时体会到的这些细节. 同步提交是 ...

  8. Comet实现的网页聊天程序

    “上一篇”介绍了我在c/s程序中用了那些技术,如今只谈c/s不谈b/s那未免out了,势必要写一写b/s的程序与大家共勉. 回忆做技术这些年,06年每天盯着“天轰穿”的视频不亦乐乎,估计那是一代程序员 ...

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

    1. 前言 Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Serve ...

  10. js021-Ajax与Comet

    js021-Ajax与Comet 本章内容: 使用XMLHttpRequet对象 使用XMLHttpRequet事件 跨域Ajax通信的限制 Ajax技术的核心是XMLHttpRequet对象 21. ...

随机推荐

  1. 分享Kali Linux 2017年第30周镜像文件

     分享Kali Linux 2017年第30周镜像文件 Kali Linux官方于7月23日发布2017年的第30周镜像.这次维持了11个镜像文件的规模.默认的Gnome桌面的4个镜像,E17.KDE ...

  2. AGC 022 C - Remainder Game

    题面在这里! 显然权值是 2^i 这种的话就是要你贪心,高位能不选就不选. 并且如果 % x 之后再去 % 一个>=x的数是没有用的,所以我们可以把操作的k看成单调递减序列. 这样的话就是一个有 ...

  3. BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1827 [题目大意] 给出一棵有点权和边权的树, 请确定一个点,使得每个点到这个点的距离 ...

  4. 【高斯消元】CDOJ1783 曜酱的线性代数课堂(一)

    高斯消元求逆矩阵板子. #include<cstdio> #include<cmath> #include<algorithm> #include<cstri ...

  5. 【折半枚举】Ural Championship April 30, 2017 Problem G. Glasses with solutions

    题意:有n杯盐溶液,给定每杯里面盐的质量以及盐溶液的质量.问你有多少种方案选择一个子集,使得集合里面的盐溶液倒到一个被子里面以后,浓度为A/B. 折半枚举,暴力搜索分界线一侧的答案数,跨越分界线的答案 ...

  6. 【单调队列DP+manacher】BZOJ2565-最长双回文串

    [题目大意] 输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串. [思路] 首先普通地求manacher,然后求出以每个位置为左端点和右端 ...

  7. [转]spring4.x注解概述

    1. 背景 注解可以减少代码的开发量,spring提供了丰富的注解功能,因项目中用到不少注解,因此下定决心,经spring4.x中涉及到的注解罗列出来,供查询使用. 2. spring注解图     ...

  8. <摘录>perl正则表达式中的元字符、转义字符、量词及匹配方式

    Linux平台上被广泛使用的正则表达式库PCRE - Perl-compatible regular expressions,从其名字即可知道,PCRE提供的是一套与Perl中相兼容的正则表达式. 元 ...

  9. 【IntelliJ IDEA】在idea上操作 git分支合并【如何将远程swagger分支 合并到 远程 master分支上】【如何切换 本地分支】

    ============================================ 明确一点: 如果项目交给git管理了[如何将项目交给git管理:https://www.cnblogs.com ...

  10. 【Tomcat MyEcplise】MyEcplise添加一个新的Server,Tomcat8.5报错

    添加新的Tomcat添加不进去,报错: The Apache Tomcat installation at this directory is version 8.5.11.  A Tomcat 8. ...