Web 通信 之 長(zhǎng)連接掀鹅、長(zhǎng)輪詢(long polling)

基于HTTP的長(zhǎng)連接,是一種通過(guò)長(zhǎng)輪詢方式實(shí)現(xiàn)"服務(wù)器推"的技術(shù),它彌補(bǔ)了HTTP簡(jiǎn)單的請(qǐng)求應(yīng)答模式的不足,極大地增強(qiáng)了程序的實(shí)時(shí)性和交互性限府。

一署穗、什么是長(zhǎng)連接、長(zhǎng)輪詢低飒?

用通俗易懂的話來(lái)說(shuō),就是客戶端不停的向服務(wù)器發(fā)送請(qǐng)求以獲取最新的數(shù)據(jù)信息。這里的“不陀馨常”其實(shí)是有停止的,只是我們?nèi)搜蹮o(wú)法分辨是否停止苍碟,它只是一種快速的停下然后又立即開(kāi)始連接而已抒钱。

二厉颤、長(zhǎng)連接帜乞、長(zhǎng)輪詢的應(yīng)用場(chǎng)景

長(zhǎng)連接资溃、長(zhǎng)輪詢一般應(yīng)用與WebIM、ChatRoom和一些需要及時(shí)交互的網(wǎng)站應(yīng)用中更米。其真實(shí)案例有:WebQQ类腮、Hi網(wǎng)頁(yè)版、Facebook IM等。

如果你對(duì)服務(wù)器端的反向Ajax感興趣乾蓬,可以參考這篇文章 DWR 反向Ajax 服務(wù)器端推的方式:http://www.cnblogs.com/hoojo/category/276235.html

三、優(yōu)缺點(diǎn)

輪詢:客戶端定時(shí)向服務(wù)器發(fā)送Ajax請(qǐng)求巧号,服務(wù)器接到請(qǐng)求后馬上返回響應(yīng)信息并關(guān)閉連接族奢。

優(yōu)點(diǎn):后端程序編寫(xiě)比較容易。

缺點(diǎn):請(qǐng)求中有大半是無(wú)用门怪,浪費(fèi)帶寬和服務(wù)器資源。

實(shí)例:適于小型應(yīng)用亏较。

長(zhǎng)輪詢:客戶端向服務(wù)器發(fā)送Ajax請(qǐng)求炉旷,服務(wù)器接到請(qǐng)求后hold住連接签孔,直到有新消息才返回響應(yīng)信息并關(guān)閉連接,客戶端處理完響應(yīng)信息后再向服務(wù)器發(fā)送新的請(qǐng)求窘行。

優(yōu)點(diǎn):在無(wú)消息的情況下不會(huì)頻繁的請(qǐng)求饥追,耗費(fèi)資源小。

缺點(diǎn):服務(wù)器hold連接會(huì)消耗資源罐盔,返回?cái)?shù)據(jù)順序無(wú)保證但绕,難于管理維護(hù)。

實(shí)例:WebQQ惶看、Hi網(wǎng)頁(yè)版捏顺、Facebook IM。

長(zhǎng)連接:在頁(yè)面里嵌入一個(gè)隱蔵iframe纬黎,將這個(gè)隱蔵iframe的src屬性設(shè)為對(duì)一個(gè)長(zhǎng)連接的請(qǐng)求或是采用xhr請(qǐng)求幅骄,服務(wù)器端就能源源不斷地往客戶端輸入數(shù)據(jù)。

優(yōu)點(diǎn):消息即時(shí)到達(dá)本今,不發(fā)無(wú)用請(qǐng)求拆座;管理起來(lái)也相對(duì)方便。

缺點(diǎn):服務(wù)器維護(hù)一個(gè)長(zhǎng)連接會(huì)增加開(kāi)銷冠息。

實(shí)例:Gmail聊天

Flash Socket:在頁(yè)面中內(nèi)嵌入一個(gè)使用了Socket類的 Flash 程序JavaScript通過(guò)調(diào)用此Flash程序提供的Socket接口與服務(wù)器端的Socket接口進(jìn)行通信挪凑,JavaScript在收到服務(wù)器端傳送的信息后控制頁(yè)面的顯示。

優(yōu)點(diǎn):實(shí)現(xiàn)真正的即時(shí)通信铐达,而不是偽即時(shí)岖赋。

缺點(diǎn):客戶端必須安裝Flash插件;非HTTP協(xié)議瓮孙,無(wú)法自動(dòng)穿越防火墻唐断。

實(shí)例:網(wǎng)絡(luò)互動(dòng)游戲。

四杭抠、實(shí)現(xiàn)原理

所謂長(zhǎng)連接脸甘,就是要在客戶端與服務(wù)器之間創(chuàng)建和保持穩(wěn)定可靠的連接。其實(shí)它是一種很早就存在的技術(shù)偏灿,但是由于瀏覽器技術(shù)的發(fā)展比較緩慢丹诀,沒(méi)有為這種機(jī)制的實(shí)現(xiàn)提供很好的支持。所以要達(dá)到這種效果,需要客戶端和服務(wù)器的程序共同配合來(lái)完成铆遭。通常的做法是硝桩,在服務(wù)器的程序中加入一個(gè)死循環(huán),在循環(huán)中監(jiān)測(cè)數(shù)據(jù)的變動(dòng)枚荣。當(dāng)發(fā)現(xiàn)新數(shù)據(jù)時(shí)碗脊,立即將其輸出給瀏覽器并斷開(kāi)連接,瀏覽器在收到數(shù)據(jù)后橄妆,再次發(fā)起請(qǐng)求以進(jìn)入下一個(gè)周期衙伶,這就是常說(shuō)的長(zhǎng)輪詢(long-polling)方式。如下圖所示害碾,它通常包含以下幾個(gè)關(guān)鍵過(guò)程:

1. 輪詢的建立

建立輪詢的過(guò)程很簡(jiǎn)單矢劲,瀏覽器發(fā)起請(qǐng)求后進(jìn)入循環(huán)等待狀態(tài),此時(shí)由于服務(wù)器還未做出應(yīng)答慌随,所以HTTP也一直處于連接狀態(tài)中芬沉。

2. 數(shù)據(jù)的推送

在循環(huán)過(guò)程中,服務(wù)器程序?qū)?shù)據(jù)變動(dòng)進(jìn)行監(jiān)控儒陨,如發(fā)現(xiàn)更新花嘶,將該信息輸出給瀏覽器,隨即斷開(kāi)連接蹦漠,完成應(yīng)答過(guò)程,實(shí)現(xiàn)“服務(wù)器推”车海。

3. 輪詢的終止

輪詢可能在以下3種情況時(shí)終止:

3.1. 有新數(shù)據(jù)推送

當(dāng)循環(huán)過(guò)程中服務(wù)器向?yàn)g覽器推送信息后笛园,應(yīng)該主動(dòng)結(jié)束程序運(yùn)行從而讓連接斷開(kāi),這樣瀏覽器才能及時(shí)收到數(shù)據(jù)侍芝。

3.2. 沒(méi)有新數(shù)據(jù)推送

循環(huán)不能一直持續(xù)下去研铆,應(yīng)該設(shè)定一個(gè)最長(zhǎng)時(shí)限,避免WEB服務(wù)器超時(shí)(Timeout)州叠,若一直沒(méi)有新信息棵红,服務(wù)器應(yīng)主動(dòng)向?yàn)g覽器發(fā)送本次輪詢無(wú)新信息的正常響應(yīng),并斷開(kāi)連接咧栗,這也被稱為“心跳”信息逆甜。

3.3. 網(wǎng)絡(luò)故障或異常

由于網(wǎng)絡(luò)故障等因素造成的請(qǐng)求超時(shí)或出錯(cuò)也可能導(dǎo)致輪詢的意外中斷,此時(shí)瀏覽器將收到錯(cuò)誤信息致板。

4. 輪詢的重建

瀏覽器收到回復(fù)并進(jìn)行相應(yīng)處理后交煞,應(yīng)馬上重新發(fā)起請(qǐng)求,開(kāi)始一個(gè)新的輪詢周期斟或。

五素征、程序設(shè)計(jì)

1、普通輪詢 Ajax方式

客戶端代碼片段
客戶端實(shí)現(xiàn)的就是用一種普通輪詢的結(jié)果,比較簡(jiǎn)單御毅。利用setInterval不間斷的刷新來(lái)獲取服務(wù)器的資源根欧,這種方式的優(yōu)點(diǎn)就是簡(jiǎn)單、及時(shí)端蛆。缺點(diǎn)是鏈接多數(shù)是無(wú)效重復(fù)的凤粗;響應(yīng)的結(jié)果沒(méi)有順序(因?yàn)槭钱惒秸?qǐng)求,當(dāng)發(fā)送的請(qǐng)求沒(méi)有返回結(jié)果的時(shí)候欺税,后面的請(qǐng)求又被發(fā)送侈沪。而此時(shí)如果后面的請(qǐng)求比前面的請(qǐng)求要先返回結(jié)果,那么當(dāng)前面的請(qǐng)求返回結(jié)果數(shù)據(jù)時(shí)已經(jīng)是過(guò)時(shí)無(wú)效的數(shù)據(jù)了)晚凿;請(qǐng)求多亭罪,難于維護(hù)、浪費(fèi)服務(wù)器和網(wǎng)絡(luò)資源歼秽。
服務(wù)器端代碼
服務(wù)器端實(shí)現(xiàn)应役,這里就模擬下程序監(jiān)控?cái)?shù)據(jù)的變化。上面代碼屬于SpringMVC 中controller中的一個(gè)方法燥筷,相當(dāng)于Servlet中的一個(gè)doPost/doGet方法箩祥。如果沒(méi)有程序環(huán)境適應(yīng)servlet即可,將方法體中的代碼copy到servlet的doGet/doPost中即可肆氓。

服務(wù)器端在進(jìn)行長(zhǎng)連接的程序設(shè)計(jì)時(shí)袍祖,要注意以下幾點(diǎn):

1. 服務(wù)器程序?qū)喸兊目煽匦?/b>

由于輪詢是用死循環(huán)的方式實(shí)現(xiàn)的,所以在算法上要保證程序?qū)螘r(shí)退出循環(huán)有完全的控制能力谢揪,避免進(jìn)入死循環(huán)而耗盡服務(wù)器資源蕉陋。

2. 合理選擇“心跳”頻率

從圖1可以看出,長(zhǎng)連接必須由客戶端不停地進(jìn)行請(qǐng)求來(lái)維持拨扶,所以在客戶端和服務(wù)器間保持正常的“心跳”至為關(guān)鍵凳鬓,參數(shù)POLLING_LIFE應(yīng)小于WEB服務(wù)器的超時(shí)時(shí)間,一般建議在10~20秒左右患民。

3. 網(wǎng)絡(luò)因素的影響

在實(shí)際應(yīng)用時(shí)缩举,從服務(wù)器做出應(yīng)答,到下一次循環(huán)的建立匹颤,是有時(shí)間延遲的仅孩,延遲時(shí)間的長(zhǎng)短受網(wǎng)絡(luò)傳輸?shù)榷喾N因素影響,在這段時(shí)間內(nèi)惋嚎,長(zhǎng)連接處于暫時(shí)斷開(kāi)的空檔杠氢,如果恰好有數(shù)據(jù)在這段時(shí)間內(nèi)發(fā)生變動(dòng),服務(wù)器是無(wú)法立即進(jìn)行推送的另伍,所以鼻百,在算法設(shè)計(jì)上要注意解決由于延遲可能造成的數(shù)據(jù)丟失問(wèn)題绞旅。

4. 服務(wù)器的性能

在長(zhǎng)連接應(yīng)用中,服務(wù)器與每個(gè)客戶端實(shí)例都保持一個(gè)持久的連接温艇,這將消耗大量服務(wù)器資源因悲,特別是在一些大型應(yīng)用系統(tǒng)中更是如此,大量并發(fā)的長(zhǎng)連接有可能導(dǎo)致新的請(qǐng)求被阻塞甚至系統(tǒng)崩潰勺爱,所以晃琳,在進(jìn)行程序設(shè)計(jì)時(shí)應(yīng)特別注意算法的優(yōu)化和改進(jìn),必要時(shí)還需要考慮服務(wù)器的負(fù)載均衡和集群技術(shù)琐鲁。

上圖是返回的結(jié)果卫旱,可以看到先發(fā)出請(qǐng)求,不一定會(huì)最先返回結(jié)果围段。這樣就不能保證順序顾翼,造成臟數(shù)據(jù)或無(wú)用的連接請(qǐng)求∧卫幔可見(jiàn)對(duì)服務(wù)器或網(wǎng)絡(luò)的資源浪費(fèi)适贸。

2、普通輪詢 iframe方式

這里的客戶端程序是利用隱藏的iframe向服務(wù)器端不停的拉取數(shù)據(jù)涝桅,將iframe獲取后的數(shù)據(jù)填充到頁(yè)面中即可拜姿。同ajax實(shí)現(xiàn)的基本原理一樣,唯一不同的是當(dāng)一個(gè)請(qǐng)求沒(méi)有響應(yīng)返回?cái)?shù)據(jù)的情況下冯遂,下一個(gè)請(qǐng)求也將開(kāi)始蕊肥,這時(shí)候前面的請(qǐng)求將被停止。如果要使程序和上面的ajax請(qǐng)求一樣也可以辦到蛤肌,那就是給每個(gè)請(qǐng)求分配一個(gè)獨(dú)立的iframe即可晴埂。下面是返回的結(jié)果:

其中紅色是沒(méi)有成功返回請(qǐng)求就被停止(后面請(qǐng)求開(kāi)始)掉的請(qǐng)求,黑色是成功返回?cái)?shù)據(jù)的請(qǐng)求寻定。

3、長(zhǎng)連接iframe方式


這個(gè)輪詢方式就是把剛才上面的稍微改下精耐,每個(gè)請(qǐng)求都有自己獨(dú)立的一個(gè)iframe狼速,當(dāng)這個(gè)iframe得到響應(yīng)的數(shù)據(jù)后就把數(shù)據(jù)push到當(dāng)前頁(yè)面上。使用此方法已經(jīng)類似于ajax的異步交互了卦停,這種方法也是不能保證順序的向胡、比較耗費(fèi)資源、而且總是有一個(gè)加載的條在地址欄或狀態(tài)欄附件(當(dāng)然要解決可以利用htmlfile惊完,Google的攻城師們已經(jīng)做到了僵芹,網(wǎng)上也有封裝好的lib庫(kù)),但客戶端實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單小槐。

如果要保證有序拇派,可以不使用setInterval荷辕,將創(chuàng)建iframe的方法放在load事件中即可,即使用遞歸方式件豌。調(diào)整后的代碼片段如下:

這種方式雖然保證了請(qǐng)求的順序疮方,但是它不會(huì)處理請(qǐng)求延時(shí)的錯(cuò)誤或是說(shuō)很長(zhǎng)時(shí)間沒(méi)有返回結(jié)果的請(qǐng)求,它會(huì)一直等到返回請(qǐng)求后才能創(chuàng)建下一個(gè)iframe請(qǐng)求茧彤,總會(huì)和服務(wù)器保持一個(gè)連接骡显。和以上輪詢比較,缺點(diǎn)就是消息不及時(shí)曾掂,但保證了請(qǐng)求的順序惫谤。

4、ajax實(shí)現(xiàn)長(zhǎng)連接


上面這段代碼就是才有Ajax的方式完成長(zhǎng)連接珠洗,主要優(yōu)點(diǎn)就是和服務(wù)器始終保持一個(gè)連接溜歪。如果當(dāng)前連接請(qǐng)求成功后,將更新數(shù)據(jù)并且繼續(xù)創(chuàng)建一個(gè)新的連接和服務(wù)器保持聯(lián)系险污。如果連接超時(shí)或發(fā)生異常痹愚,這個(gè)時(shí)候程序也會(huì)創(chuàng)建一個(gè)新連接繼續(xù)請(qǐng)求。這樣就大大節(jié)省了服務(wù)器和網(wǎng)絡(luò)資源蛔糯,提高了程序的性能拯腮,從而也保證了程序的順序。

六蚁飒、總結(jié)

現(xiàn)代的瀏覽器都支持跨域資源共享(Cross-Origin Resource Share动壤,CORS)規(guī)范,該規(guī)范允許XHR執(zhí)行跨域請(qǐng)求淮逻,因此基于腳本的和基于iframe的技術(shù)已成為了一種過(guò)時(shí)的需要琼懊。

把Comet做為反向Ajax的實(shí)現(xiàn)和使用的最好方式是通過(guò)XMLHttpRequest對(duì)象,該做法提供了一個(gè)真正的連接句柄和錯(cuò)誤處理爬早。當(dāng)然你選擇經(jīng)由HTTP長(zhǎng)輪詢使用XMLHttpRequest對(duì)象(在服務(wù)器端掛起的一個(gè)簡(jiǎn)單的Ajax請(qǐng)求)的Comet模式哼丈,所有支持Ajax的瀏覽器也都支持該種做法。

基于HTTP的長(zhǎng)連接技術(shù)筛严,是目前在純?yōu)g覽器環(huán)境下進(jìn)行即時(shí)交互類應(yīng)用開(kāi)發(fā)的理想選擇醉旦,隨著瀏覽器的快速發(fā)展,html5將為其提供更好的支持和更廣泛的應(yīng)用桨啃。在html5中有一個(gè)websocket 可以很友好的完成長(zhǎng)連接這一技術(shù)车胡,網(wǎng)上也有相關(guān)方面的資料,這里也就不再做過(guò)多介紹照瘾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匈棘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子析命,更是在濱河造成了極大的恐慌主卫,老刑警劉巖逃默,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異队秩,居然都是意外死亡笑旺,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)馍资,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)筒主,“玉大人,你說(shuō)我怎么就攤上這事鸟蟹∥诿睿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵建钥,是天一觀的道長(zhǎng)藤韵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)熊经,這世上最難降的妖魔是什么泽艘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮镐依,結(jié)果婚禮上匹涮,老公的妹妹穿的比我還像新娘。我一直安慰自己槐壳,他們只是感情好然低,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著务唐,像睡著了一般雳攘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枫笛,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天吨灭,我揣著相機(jī)與錄音,去河邊找鬼刑巧。 笑死沃于,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的海诲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼檩互,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼特幔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起闸昨,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蚯斯,失蹤者是張志新(化名)和其女友劉穎薄风,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拍嵌,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遭赂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了横辆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撇他。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狈蚤,靈堂內(nèi)的尸體忽然破棺而出困肩,到底是詐尸還是另有隱情,我是刑警寧澤脆侮,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布锌畸,位于F島的核電站,受9級(jí)特大地震影響靖避,放射性物質(zhì)發(fā)生泄漏潭枣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一幻捏、第九天 我趴在偏房一處隱蔽的房頂上張望盆犁。 院中可真熱鬧,春花似錦粘咖、人聲如沸蚣抗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翰铡。三九已至,卻和暖如春讽坏,著一層夾襖步出監(jiān)牢的瞬間锭魔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工路呜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留迷捧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓胀葱,卻偏偏與公主長(zhǎng)得像漠秋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子抵屿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容