自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用Node.js搭建最簡(jiǎn)單的comet原型

開(kāi)發(fā) 前端
Comet, 據(jù)IBM這篇文章介紹,是基于HTTP長(zhǎng)連接的“服務(wù)器推”技術(shù). 和AJAX類似, 這是一種改善WEB用戶體驗(yàn)的通訊技術(shù). 其實(shí)早在CGI盛行的時(shí)代, 有種叫做"Server-Push"的技術(shù), 和Comet本質(zhì)是一回事, 都是基于長(zhǎng)連接來(lái)實(shí)現(xiàn). Server-Push更具體, 強(qiáng)調(diào)使用multipart/x-mixed-replace的Conent-Type技巧, 使得服務(wù)器能替換瀏覽器的內(nèi)容. Comet包含面更廣泛, 只要是有長(zhǎng)連接和HTTP chunked的實(shí)現(xiàn), 都算作其中. 這篇文章詳細(xì)介紹了Comet的各種形態(tài),值得一讀

什么是Comet

Comet, 據(jù)IBM這篇文章介紹,是基于HTTP長(zhǎng)連接的“服務(wù)器推”技術(shù). 和AJAX類似, 這是一種改善WEB用戶體驗(yàn)的通訊技術(shù). 其實(shí)早在CGI盛行的時(shí)代, 有種叫做"Server-Push"的技術(shù), 和Comet本質(zhì)是一回事, 都是基于長(zhǎng)連接來(lái)實(shí)現(xiàn). Server-Push更具體, 強(qiáng)調(diào)使用multipart/x-mixed-replace的Conent-Type技巧, 使得服務(wù)器能替換瀏覽器的內(nèi)容. Comet包含面更廣泛, 只要是有長(zhǎng)連接和HTTP chunked的實(shí)現(xiàn), 都算作其中. 這篇文章詳細(xì)介紹了Comet的各種形態(tài),值得一讀.

51CTO推薦專題:Node.js專區(qū)

Comet雖然能讓瀏覽器達(dá)到及時(shí)的響應(yīng), 但是由于基于長(zhǎng)連接實(shí)現(xiàn), 服務(wù)器成本很高. 最近這種技術(shù)之所以火起來(lái), 主要還是牛人們探索到了各種降低服務(wù)器成本的方法. 這個(gè)叫amix的家伙對(duì)此有較多的研究.

什么是NodeJs

nodejs號(hào)稱Evented I/O for V8 JavaScript, 是基于V8的一款神器, 讓我們可以使用javascript輕松進(jìn)行服務(wù)器端編程.

最簡(jiǎn)單的Comet原型

我用一下午的時(shí)間, 使用nodejs搞了一個(gè)簡(jiǎn)單的不能再簡(jiǎn)單的Comet原型. 在這個(gè)demo里面, 我假定使用iframe實(shí)現(xiàn)Comet, 但是忽略了iframe的父窗口和客戶端js庫(kù), 只考慮服務(wù)器如何將HTTP chunked push到客戶端.

我定義了一種Comet資源: http://{host}/{pathname}?[{query_string}] . 其中{pathname}直接當(dāng)作客戶端id來(lái)使用(在程序里面它被叫做resid). {query_string}用來(lái)做消息內(nèi)容. 這樣, 原型就簡(jiǎn)化成了兩種操作:

HTTP GET : http://{host}/{pathname} 用來(lái)模擬iframe長(zhǎng)連接, 不斷接收到新數(shù)據(jù).

HTTP PUT : http://{host}/{pathname}?{query_string} 用來(lái)模擬業(yè)務(wù)操作, 直接將{query_string}當(dāng)作數(shù)據(jù)投遞到上面的長(zhǎng)連接里面.

具體實(shí)現(xiàn)

好, 主角登場(chǎng), 用nodejs實(shí)現(xiàn)最簡(jiǎn)單的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 http://127.0.0.1:18124/'); 

測(cè)試方法

上面的代碼保存到文件, 我們?cè)诘谝粋€(gè)終端啟動(dòng)這個(gè)服務(wù):

  1. shell> node hello.js 

我們?cè)诘诙€(gè)終端模擬iframe的數(shù)據(jù)流.輸入命令, 觀察收到的數(shù)據(jù):

  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 

我們?cè)诘谌齻€(gè)終端輸入curl -X PUT命令, 模擬發(fā)送兩條消息:

  1. shell> curl -X PUT "http://127.0.0.1:18124/mymessages?a=1&b=2&c=3" 
  2. ok  
  3. shell> curl -X PUT "http://127.0.0.1:18124/mymessages?a=4&b=5&c=6" 
  4. ok 

觀察第二個(gè)終端, 會(huì)發(fā)現(xiàn)已經(jīng)收到兩條HTTP chunked. (為了避免測(cè)試數(shù)據(jù)小于MTU, 我實(shí)際上多輸出了一些空格,但這里省去了.)

  1. 202  
  2. a=1&b=2&c=3  
  3. 202  
  4. a=4&b=5&c=6 

總結(jié)

在這個(gè)原型中, 我省掉了Comet iframe方案內(nèi)無(wú)關(guān)緊要的東西, 只用HTTP PUT/GET來(lái)演示一個(gè)最簡(jiǎn)單的原型. 用NodeJs輕松搭建了它.

可以看到, 用javascript event的風(fēng)格寫(xiě)服務(wù)器, 簡(jiǎn)直是明白如話, 散文那樣自然.

我用global.messages對(duì)象來(lái)存儲(chǔ)消息, key是resid(上面說(shuō)的客戶端id), value是個(gè)array, 里面存儲(chǔ)客戶端收到的messages.

我為GET/PUT兩種操作分別實(shí)現(xiàn)了兩個(gè)函數(shù).

PUT函數(shù), 收到請(qǐng)求就將query_string當(dāng)作message存到對(duì)應(yīng)resid的array中, 然后斷開(kāi)HTTP連接.

GET函數(shù), 收到請(qǐng)求就啟動(dòng)一個(gè)定時(shí)器, 輪詢global.messages里面自己的消息隊(duì)列(array). 如果遇到數(shù)據(jù)則在HTTP response輸出http chunked. HTTP連接不主動(dòng)關(guān)閉, 但如果被異常關(guān)閉則清除定時(shí)器對(duì)象.

就這么一個(gè)簡(jiǎn)單功能, 如果用C和select來(lái)開(kāi)發(fā), 那么一個(gè)全局的客戶端句柄隊(duì)列是免不了要實(shí)現(xiàn)的, 當(dāng)io事件到來(lái)時(shí), 如何恢復(fù)之前中斷的上下文,進(jìn)行正確的io操作, 也是一件頭疼的事情.

而我們看這個(gè)實(shí)現(xiàn)里面的myoutput定時(shí)器函數(shù). 由于局部變量resid,response在函數(shù)的定義時(shí)環(huán)境內(nèi), 所以函數(shù)被執(zhí)行時(shí), 很自然就使用這些上下文信息. 相比來(lái)說(shuō), C的實(shí)現(xiàn)里面專門為此設(shè)計(jì)一個(gè)客戶端句柄隊(duì)列就太突兀了.

javascript通過(guò)函數(shù)式和閉包, 輕而易舉的完成了一個(gè)非阻塞服務(wù)器. 如果說(shuō)libevent是通過(guò)庫(kù)來(lái)實(shí)現(xiàn)了事件的封裝, 那么nodejs所宣稱的"Evented I/O for V8 JavaScript", 則是借語(yǔ)言本身的優(yōu)雅特性獲得自然的收獲.

原文:http://club.cnodejs.org/topic/4f16442ccae1f4aa27001115

【編輯推薦】

  1. 什么是Node.js?
  2. Node.js初探之hello world
  3. 揭秘Node.js事件
  4. 走近Node.js的異步代碼設(shè)計(jì)
  5. Node.js提速指南
責(zé)任編輯:陳貽新 來(lái)源: duzhigang的博客
相關(guān)推薦

2020-03-17 13:24:04

微服務(wù)架構(gòu)數(shù)據(jù)

2023-04-07 09:07:11

2018-08-30 16:08:37

Node.js腳手架工具

2018-06-11 14:39:57

前端腳手架工具node.js

2020-10-12 08:06:28

HTTP 服務(wù)器證書(shū)

2022-08-28 16:30:34

Node.jsDocker指令

2023-01-10 14:11:26

2013-11-01 09:34:56

Node.js技術(shù)

2015-03-10 10:59:18

Node.js開(kāi)發(fā)指南基礎(chǔ)介紹

2020-02-25 12:27:59

Node.jsWeb開(kāi)發(fā)前端

2021-01-14 10:48:34

Docker CompNode.js開(kāi)發(fā)

2020-05-29 15:33:28

Node.js框架JavaScript

2012-02-03 09:25:39

Node.js

2021-12-25 22:29:57

Node.js 微任務(wù)處理事件循環(huán)

2021-03-03 06:39:05

Nodejs前端開(kāi)發(fā)

2021-07-16 04:56:03

NodejsAddon

2012-09-29 11:13:15

Node.JS前端開(kāi)發(fā)Node.js打包

2021-07-30 11:20:53

JavaScriptNode.jsWeb Develop

2016-08-25 21:28:04

前端node截圖

2022-08-22 07:26:32

Node.js微服務(wù)架構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)