<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://www.jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://www.jackxiang.com/post//</link>
<title><![CDATA[使用Node.js和Redis实现push服务,使用Node.js搭建最简单的comet原型。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[WEB2.0]]></category>
<pubDate>Wed, 20 Feb 2013 13:48:05 +0000</pubDate> 
<guid>http://www.jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	画图包：http://www.rgraph.net/docs/updating-charts-dynamically.html<br/><br/>raspberry安装java：http://www.simonzhang.net/?p=1530<br/>redius node.js push:http://blog.csdn.net/unityoxb/article/details/8532028<br/><br/>push服务是一项很有用处的技术，它能改善交互，提升用户体验。要实现这项服务通常有两种途径，轮询和长连接。轮询就是客户端每隔一段时间就问服务器拿新数据，实现起来很简单但是服务器压力很大，而且大部分请求因为没有新数据都显得很浪费。长连接则是服务器将一个请求挂起，不输出任何内容，直到有新数据产生后才会完成这个请求，浏览器收到响应后则马上再发一个又让服务器挂住，如此反复。这么做的好处是能节省很多无用的请求，但是它不能使用传统的服务端软件，比如apache和php-fpm，客户端多了的话很容易把所有进程占光，这样服务器就没法响应新的请求了。<br/><br/>Node.js让这一切变得简单，它是基于事件和非阻塞I/O的服务器技术，能使用极少的资源响应大量并发的请求，非常适合长连接的要求。但是这样做还存在两个问题。首先你的服务端通常是用另外一套语言和框架做的，有成熟的代码和业务逻辑，为了实现这个push功能，难道又要用javascript来写一套吗？维护起来不嫌麻烦？其次，服务端把请求挂起后，也是不断地重复调用其它服务来获取新数据，这不过是把轮询的代码换个位置而已，本质上没区别，对服务器一样有压力。<br/><br/>有没有什么简单的办法来实现高效的push呢？<br/><br/>答案是有，而且很简单，所需代码不超过20行！<br/><br/>首先我们借助Redis的Pub/Sub功能来实现真正的push，其次用JSON来作为客户端和服务端沟通的数据格式。<br/><br/>当Node.js收到请求后，我们将请求挂起，同时实例化一个Redis客户端，并根据请求里的参数来收听一个特定的频道，原有的服务端代码（比如PHP）处理完业务逻辑后，将新数据用JSON封装下发布到这个频道，Node.js收到消息后将其作为响应传给客户端，这样就完成了一次push。代码如下<br/><br/><textarea name="code" class="php" rows="15" cols="100">
var http = require(&#039;http&#039;);
var url = require(&#039;url&#039;);
var redis = require(&#039;redis&#039;);
http.createServer(function (req, res) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;var query = url.parse(req.url, true).query;
&nbsp;&nbsp;&nbsp;&nbsp;if(typeof query.channel == &#039;undefined&#039;)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.writeHead(200, &#123;&#039;Content-Type&#039;: &#039;text/plain&#039;&#125;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.end(&#039;Invalid Request&#92;n&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&#125;else&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var client = redis.createClient(6379, &#039;127.0.0.1&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client.subscribe(query.channel);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client.on(&#039;message&#039;, function(channel, message)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.writeHead(200, &#123;&#039;Content-Type&#039;: &#039;application/json&#039;&#125;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.end(message);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client.unsubscribe();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client.end();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;);
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&#125;).listen(1337, &#039;127.0.0.1&#039;);
</textarea><br/><br/>这个方法简单易用，你只需要定好一个频道和数据关系的协议，然后对现有代码做些简单修改，就能实现一个高效的push服务了！<br/>来自：http://blog.pengqi.me/2012/12/30/implement-push-service-using-node.js-and-redis/<br/><br/><br/>来自：http://www.gridshore.nl/2011/07/28/combining-java-and-node-js-through-redis-pubsub-and-a-json-remote-interface/<br/><br/><br/><br/>使用Node.js搭建最简单的comet原型：<br/><textarea name="code" class="JS" rows="15" cols="100">
global.messages = &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;//&#039;resid&#039;:[]&nbsp;&nbsp;
&#125;;&nbsp;&nbsp;
var char500 = (function()&#123; var i=0; var arr = []; for(i=0; i&lt;500; i++) &#123; arr.push( &#039; &#039; ); &#125; return arr.join(&#039;&#039;); &#125;)();&nbsp;&nbsp;
var http_method_funs = &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#039;GET&#039;: function(resid, data, request, response) &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(global.messages[resid] == undefined) &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;global.messages[resid] = [];&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.writeHead(200, &#123;&#039;content-type&#039;: &#039;text/plain&#039;&#125;);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var interval = setInterval(myoutput, 500 );&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.connection.on(&#039;end&#039;, function()&#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&quot;GET&#92;t&quot; + resid + &quot;&#92;tclosed&quot;);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clearInterval(interval);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myoutput();&nbsp;&nbsp;
function myoutput()&#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var msgs = global.messages[resid];&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(msgs.length)&#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var str = msgs.join(&quot;&#92;n&#92;n&#92;n&quot;) + &quot;&#92;n&#92;n&#92;n&quot;;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str = (str.length &lt; 500 ) ? ( str + char500 ) : str; //for MTU&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.write(str);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;global.messages[resid] = [];&nbsp;&nbsp;
 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;,&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#039;PUT&#039;: function(resid, data , request, response) &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(global.messages[resid] == undefined) &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;global.messages[resid] = [];&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;global.messages[resid].push(data);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(global.messages);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;response.writeHead(200, &#123;&#039;content-type&#039;: &#039;text/plain&#039;&#125;);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end( &#039;ok&#92;n&#039;);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;,&nbsp;&nbsp;
&#125;;&nbsp;&nbsp;
//method function&nbsp;&nbsp; 
require(&#039;http&#039;).createServer(function (request, response) &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var urlinfo = require(&#039;url&#039;).parse(request.url);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var resid = urlinfo[&#039;pathname&#039;];&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var data = (urlinfo[&#039;query&#039;]) ? urlinfo[&#039;query&#039;] : 0 ;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var method = request.method;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(method + &quot;&#92;t&quot; + resid );&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(typeof http_method_funs[method] == &#039;function&#039;) &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http_method_funs[method].call(null, resid, data, request, response);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.writeHead(400);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end(&quot;unsupport method&#92;n&quot;);&nbsp;&nbsp;
 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;).listen(18124);&nbsp;&nbsp;
console.log(&#039;server running at http://127.0.0.1:18124/&#039;); 

</textarea><br/><br/>测试方法<br/><br/>上面的代码保存到文件, 我们在第一个终端启动这个服务:<br/>shell&gt; node hello.js <br/>我们在第二个终端模拟iframe的数据流.输入命令, 观察收到的数据（这儿在raspberry pi上get无返回）:<br/>telnet 127.0.0.1 18124&nbsp;&nbsp;<br/>GET /mymessages HTTP/1.1&nbsp;&nbsp;<br/>HTTP/1.1 200 OK&nbsp;&nbsp;<br/>content-type: text/plain&nbsp;&nbsp;<br/>Connection: keep-alive&nbsp;&nbsp;<br/>Transfer-Encoding: chunked <br/>我们在第三个终端输入curl -X PUT命令, 模拟发送两条消息:<br/><br/>shell&gt; curl -X PUT &quot;http://127.0.0.1:18124/mymessages?a=1&amp;b=2&amp;c=3&quot; <br/>ok&nbsp;&nbsp;<br/>shell&gt; curl -X PUT &quot;http://127.0.0.1:18124/mymessages?a=4&amp;b=5&amp;c=6&quot; <br/>ok <br/>观察第二个终端, 会发现已经收到两条HTTP chunked. (为了避免测试数据小于MTU, 我实际上多输出了一些空格,但这里省去了.)<br/>202&nbsp;&nbsp;<br/>a=1&amp;b=2&amp;c=3&nbsp;&nbsp;<br/>202&nbsp;&nbsp;<br/>a=4&amp;b=5&amp;c=6 <br/>来自：http://developer.51cto.com/art/201202/315327.htm<br/><br/><br/>而上面这个是属于Node.js实现的后端（当然这个也可以用Nginx的Push，这个Push不是一条链接，是要换一下，但实时性还是不错的），而前端怎么弄呢？【Nginx的Push参考这个： http://code.adrianvera.com/comet-server-nginx-push-ubuntu-11.10 ，我前面的个人博客了呢写，自己虚拟机里有陪着好的可以参考。】<br/><br/>前端参考这一段代码：<br/><textarea name="code" class="JS" rows="15" cols="100">
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Information about updating your charts dynamically&lt;/title&gt;
&lt;meta name=&quot;description&quot; content=&quot;How you can update your charts dynamically using AJAX. AJAX may be a preferable method to use in place of refreshing the whole page. RGraph contains a method specifically for AJAX - RGraph.AJAX(url, callback).&quot; /&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&lt;script src=&quot;http://javascript.www.rgraph.net/libraries/combined.html/RGraph.common.core.js/RGraph.common.effects.js/RGraph.common.context.js/RGraph.line.js&quot; &gt;&lt;/script&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--[if lt IE 9]&gt;&lt;script src=&quot;http://javascript.www.rgraph.net/libraries/combined.html/excanvas.js&quot;&gt;&lt;/script&gt;&lt;![endif]--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;link rel=&quot;alternate&quot; type=&quot;application/rss+xml&quot; href=&quot;http://www.rgraph.net/news.xml&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;http://css.www.rgraph.net/css/website.css&quot; type=&quot;text/css&quot; media=&quot;screen&quot; /&gt;&lt;link rel=&quot;icon&quot; type=&quot;image/png&quot; href=&quot;http://images.www.rgraph.net/images/favicon.png&quot;&gt;&lt;link rel=&quot;author&quot; rel=&quot;me&quot; href=&quot;https://plus.google.com/106209632170546599952&quot; /&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&lt;meta name=&quot;googlebot&quot; content=&quot;NOODP&quot;&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&lt;meta property=&quot;og:title&quot; content=&quot;RGraph - Free HTML5/Javascript charts and graphs&quot; /&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;meta property=&quot;og:description&quot; content=&quot;A free Javascript charting library based on the HTML5 canvas tag. RGraph can produce over 20 different kinds of charts.&quot; /&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;meta property=&quot;og:image&quot; content=&quot;http://images.www.rgraph.net/images/logo.png&quot;/&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;script&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var _gaq = _gaq &#124;&#124; [];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_gaq.push([&#039;_setAccount&#039;, &#039;UA-54706-2&#039;]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_gaq.push([&#039;_trackPageview&#039;]);
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(function() &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var ga = document.createElement(&#039;script&#039;); ga.type = &#039;text/javascript&#039;; ga.async = true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ga.src = (&#039;https:&#039; == document.location.protocol ? &#039;https://ssl&#039; : &#039;http://www&#039;) + &#039;.google-analytics.com/ga.js&#039;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var s = document.getElementsByTagName(&#039;script&#039;)[0]; s.parentNode.insertBefore(ga, s);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;)();
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div style=&quot;float: right&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;canvas id=&quot;cvs&quot; width=&quot;600&quot; height=&quot;250&quot; style=&quot;cursor: default;&quot;&gt;[No canvas support]&lt;/canvas&gt;&lt;br&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span style=&quot;margin-left: 25px&quot;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Number of updates: &lt;span id=&quot;num_updates&quot;&gt;132&lt;/span&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/span&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt;

&lt;script&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.onload = function (e)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1&nbsp;&nbsp;= [];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;l&nbsp;&nbsp; = 0; // The letter &#039;L&#039; - NOT a one
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Pre-pad the arrays with null values
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (var i=0; i&lt;600; ++i) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1.push(null);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function getGraph(id, d1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// After creating the chart, store it on the global window object
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!window.__rgraph_line__) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__ = new RGraph.Line(id, d1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.xticks&#039;, 100);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.background.barcolor1&#039;, &#039;white&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.background.barcolor2&#039;, &#039;white&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.title.xaxis&#039;, &#039;Time &gt;&gt;&gt;&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.title.yaxis&#039;, &#039;Bandwidth (MB/s)&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.title.vpos&#039;, 0.5);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.title&#039;, &#039;Bandwidth used&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.title.yaxis.pos&#039;, 0.5);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.title.xaxis.pos&#039;, 0.5);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.colors&#039;, [&#039;black&#039;]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.linewidth&#039;,0.5);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//obj.Set(&#039;chart.ylabels.inside&#039;, true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.yaxispos&#039;, &#039;right&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.ymax&#039;, 50);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.xticks&#039;, 25);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.filled&#039;, true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var grad = window.__rgraph_line__.context.createLinearGradient(0,0,0,250);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;grad.addColorStop(0, &#039;#efefef&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;grad.addColorStop(0.9, &#039;rgba(0,0,0,0)&#039;);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.Set(&#039;chart.fillstyle&#039;, [grad]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return window.__rgraph_line__;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function drawGraph ()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Update the HTML counter - this is totally optional
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.getElementById(&quot;num_updates&quot;).innerHTML = parseInt(document.getElementById(&quot;num_updates&quot;).innerHTML) + 1;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RGraph.Clear(document.getElementById(&quot;cvs&quot;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var graph = getGraph(&#039;cvs&#039;, d1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;graph.Draw();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Add some data to the data arrays
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var r1 = RGraph.random(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGraph.is_null(d1[d1.length - 1]) ? 26 : d1[d1.length - 1] - 2,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RGraph.is_null(d1[d1.length - 1]) ? 24 : d1[d1.length - 1] + 2
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r1 = Math.max(r1, 0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r1 = Math.min(r1, 50);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1.push(r1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (d1.length &gt; 600) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d1 = RGraph.array_shift(d1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (document.all &amp;&amp; RGraph.isIE8()) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&#039;[MSIE] Sorry, Internet Explorer 8 is not fast enough to support animated charts&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.__rgraph_line__.original_data[0] = d1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(drawGraph, 50);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drawGraph();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/script&gt;
</textarea><br/>
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] 使用Node.js和Redis实现push服务,使用Node.js搭建最简单的comet原型。]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>