摘要:Comet, 是基于HTTP长连接的“服务器推”技术.。和AJAX类似,,这是一种改善WEB用户体验的通讯技术。希望阅读本篇文章以后大家有所收获,帮助大家对Node.js的理解更加深入。
什么是Comet
Comet, 是基于HTTP长连接的“服务器推”技术. 和AJAX类似, 这是一种改善WEB用户体验的通讯技术. 其实早在CGI盛行的时代, 有种叫做"Server-Push"的技术, 和Comet本质是一回事, 都是基于长连接来实现. Server-Push更具体, 强调使用multipart/x-mixed-replace的Conent-Type技巧, 使得服务器能替换浏览器的内容. Comet包含面更广泛, 只要是有长连接和HTTP chunked的实现, 都算作其中. 这篇文章详细介绍了Comet的各种形态,值得一读.
Comet虽然能让浏览器达到及时的响应, 但是由于基于长连接实现, 服务器成本很高. 最近这种技术之所以火起来, 主要还是牛人们探索到了各种降低服务器成本的方法. 这个叫amix的家伙对此有较多的研究.
什么是NodeJs
nodejs号称Evented I/O for V8 JavaScript, 是基于V8的一款神器, 让我们可以使用javascript轻松进行服务器端编程.
最简单的Comet原型
我用一下午的时间, 使用nodejs搞了一个简单的不能再简单的Comet原型. 在这个demo里面, 我假定使用iframe实现Comet, 但是忽略了iframe的父窗口和客户端js库, 只考虑服务器如何将HTTP chunked push到客户端.
我定义了一种Comet资源: //{host}/{pathname}?[{query_string}] . 其中{pathname}直接当作客户端id来使用(在程序里面它被叫做resid). {query_string}用来做消息内容. 这样, 原型就简化成了两种操作:
HTTP GET : //{host}/{pathname} 用来模拟iframe长连接, 不断接收到新数据.
HTTP PUT : //{host}/{pathname}?{query_string} 用来模拟业务操作, 直接将{query_string}当作数据投递到上面的长连接里面.
具体实现
好, 主角登场, 用nodejs实现最简单的Comet:
1. global.messages = { 2. //'resid':[] 3. }; 4. var char500 = (function(){ var i=0; var arr = []; for(i=0; i<500; i++) { arr.push( ' ' ); } return arr.join(''); })(); 5. var http_method_funs = { 6. 'GET': function(resid, data, request, response) { 7. if(global.messages[resid] == undefined) { 8. global.messages[resid] = []; 9. } 10. response.writeHead(200, {'content-type': 'text/plain'}); 11. var interval = setInterval(myoutput, 500 ); 12. response.connection.on('end', function(){ 13. console.log("GET\t" + resid + "\tclosed"); 14. clearInterval(interval); 15. }); 16. myoutput(); 17. function myoutput(){ 18. var msgs = global.messages[resid]; 19. if(msgs.length){ 20. var str = msgs.join("\n\n\n") + "\n\n\n"; 21. str = (str.length < 500 ) ? ( str + char500 ) : str; //for MTU 22. response.write(str); 23. global.messages[resid] = []; 24. 25. } 26. } 27. }, 28. 'PUT': function(resid, data , request, response) { 29. if(global.messages[resid] == undefined) { 30. global.messages[resid] = []; 31. } 32. global.messages[resid].push(data); 33. console.log(global.messages); 34. response.writeHead(200, {'content-type': 'text/plain'}); 35. response.end( 'ok\n'); 36. }, 37. }; 38. //method function 39. require('http').createServer(function (request, response) { 40. var urlinfo = require('url').parse(request.url); 41. var resid = urlinfo['pathname']; 42. var data = (urlinfo['query']) ? urlinfo['query'] : 0 ; 43. var method = request.method; 44. console.log(method + "\t" + resid ); 45. if(typeof http_method_funs[method] == 'function') { 46. http_method_funs[method].call(null, resid, data, request, response); 47. } 48. else { 49. response.writeHead(400); 50. response.end("unsupport method\n"); 51. 52. } 53. }).listen(18124); 54. console.log('server running at //127.0.0.1:18124/');
测试方法
上面的代码保存到文件, 我们在第一个终端启动这个服务:
shell> node hello.js
我们在第二个终端模拟iframe的数据流.输入命令, 观察收到的数据:
1. telnet 127.0.0.1 18124 2. GET /mymessages HTTP/1.1 3. HTTP/1.1 200 OK 4. content-type: text/plain 5. Connection: keep-alive 6. Transfer-Encoding: chunked
我们在第三个终端输入curl -X PUT命令, 模拟发送两条消息:
1. shell> curl -X PUT "//127.0.0.1:18124/mymessages?a=1&b=2&c=3" 2. ok 3. shell> curl -X PUT "//127.0.0.1:18124/mymessages?a=4&b=5&c=6" 4. ok
观察第二个终端, 会发现已经收到两条HTTP chunked. (为了避免测试数据小于MTU, 我实际上多输出了一些空格,但这里省去了.)
1. 202 2. a=1&b=2&c=3 3. 202 4. a=4&b=5&c=6
总结
在这个原型中, 我省掉了Comet iframe方案内无关紧要的东西, 只用HTTP PUT/GET来演示一个最简单的原型. 用NodeJs轻松搭建了它.
可以看到, 用javascript event的风格写服务器, 简直是明白如话, 散文那样自然.
我用global.messages对象来存储消息, key是resid(上面说的客户端id), value是个array, 里面存储客户端收到的messages.
我为GET/PUT两种操作分别实现了两个函数.
PUT函数, 收到请求就将query_string当作message存到对应resid的array中, 然后断开HTTP连接.
GET函数, 收到请求就启动一个定时器, 轮询global.messages里面自己的消息队列(array). 如果遇到数据则在HTTP response输出http chunked. HTTP连接不主动关闭, 但如果被异常关闭则清除定时器对象.
就这么一个简单功能, 如果用C和select来开发, 那么一个全局的客户端句柄队列是免不了要实现的, 当io事件到来时, 如何恢复之前中断的上下文,进行正确的io操作, 也是一件头疼的事情.
而我们看这个实现里面的myoutput定时器函数. 由于局部变量resid,response在函数的定义时环境内, 所以函数被执行时, 很自然就使用这些上下文信息. 相比来说, C的实现里面专门为此设计一个客户端句柄队列就太突兀了.
javascript通过函数式和闭包, 轻而易举的完成了一个非阻塞服务器. 如果说libevent是通过库来实现了事件的封装, 那么nodejs所宣称的"Evented I/O for V8 JavaScript", 则是借语言本身的优雅特性获得自然的收获.
本文由职坐标整理并发布,了解更多内容,请关注职坐标WEB前端Node.js频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号