服务器 主动 推送 客户端浏览器 消息***
前言
通常情況下,無論是web瀏覽器還是移動app,我們與服務(wù)器之間的交互都是主動的,客戶端向服務(wù)器端發(fā)出請求,然后服務(wù)器端返回數(shù)據(jù)給客戶端,客戶端瀏覽器再將信息呈現(xiàn),客戶端與服務(wù)端對應(yīng)的模式是: 客戶端請求--服務(wù)端響應(yīng),這種機(jī)制對于信息變化不是特別頻繁的應(yīng)用尚可,但對于實(shí)時要求高、海量并發(fā)的應(yīng)用來說顯得捉襟見肘,尤其在當(dāng)前業(yè)界移動互聯(lián)網(wǎng)蓬勃發(fā)展的趨勢下,高并發(fā)與用戶實(shí)時響應(yīng)是 Web 應(yīng)用經(jīng)常面臨的問題,比如金融證券的實(shí)時信息,Web 導(dǎo)航應(yīng)用中的地理位置獲取,社交網(wǎng)絡(luò)的實(shí)時消息推送,新聞的訂閱,天氣的提醒等。這些情況下,需要服務(wù)器主動推送消息給客戶端。
那么在這樣的模式下,會有幾個問題需要我們思考下:
1.應(yīng)用服務(wù)器如何確定每一個應(yīng)用所在的設(shè)備
2.服務(wù)器端是如何將消息推送到客戶端的,客戶端又不像服務(wù)器有一個固定的地址
帶著這些疑問我們來研究一下目前有哪些技術(shù)可以解決該問題:
一、Ajax輪詢
所謂的Ajax輪詢,其實(shí)就是定時的通過Ajax查詢服務(wù)端,客戶端按規(guī)定時間定時像服務(wù)端發(fā)送ajax請求,服務(wù)器接到請求后馬上返回響應(yīng)信息并關(guān)閉連接。
這種技術(shù)方式實(shí)現(xiàn)起來非常簡單,但是這種方式會有非常嚴(yán)重的問題,就是需要不斷的向服務(wù)器發(fā)送消息詢問,這種方式會對服務(wù)器造成極大的性能浪費(fèi)。
還有一個類似的輪詢是使用JSONP跨域請求的方式輪詢,在實(shí)現(xiàn)起來有差別,但基本原理都是相同的,都是客戶端不斷的向服務(wù)器發(fā)起請求。
優(yōu)點(diǎn)
實(shí)現(xiàn)簡單。
缺點(diǎn)
這是通過模擬服務(wù)器發(fā)起的通信,不是實(shí)時通信,不顧及應(yīng)用的狀態(tài)改變而盲目檢查更新,導(dǎo)致服務(wù)器資源的浪費(fèi),且會加重網(wǎng)絡(luò)負(fù)載,拖累服務(wù)器。
二、Comet
Comet,基于 HTTP 長連接的?"服務(wù)器推" 技術(shù),能使服務(wù)器端主動以異步的方式向客戶端程序推送數(shù)據(jù),而不需要客戶端顯式的發(fā)出請求,目前有兩種實(shí)現(xiàn)方式:
1.?基于 AJAX 的長輪詢(long-polling)方式
Ajax 的出現(xiàn)使得 JavaScript 可以調(diào)用 XMLHttpRequest 對象發(fā)出 HTTP 請求,JavaScript 響應(yīng)處理函數(shù)根據(jù)服務(wù)器返回的信息對 HTML 頁面的顯示進(jìn)行更新。使用 AJAX 實(shí)現(xiàn) "服務(wù)器推" 與傳統(tǒng)的 AJAX 應(yīng)用不同之處在于:
- 服務(wù)器端會阻塞請求直到有數(shù)據(jù)傳遞或超時才返回。
- 客戶端 JavaScript 響應(yīng)處理函數(shù)會在處理完服務(wù)器返回的信息后,再次發(fā)出請求,重新建立連接。
- 當(dāng)客戶端處理接收的數(shù)據(jù)、重新建立連接時,服務(wù)器端可能有新的數(shù)據(jù)到達(dá);這些信息會被服務(wù)器端保存直到客戶端重新建立連接,客戶端會一次把當(dāng)前服務(wù)器端所有的信息取回。
基于長輪詢的服務(wù)器推模型
?
?
相對于"輪詢"(poll),這種長輪詢方式也可以稱為"拉"(pull)。因?yàn)檫@種方案基于 AJAX,具有以下一些優(yōu)點(diǎn):請求異步發(fā)出;無須安裝插件;IE、Mozilla FireFox 都支持 AJAX。
長輪詢 (long polling) 是在打開一條連接以后保持并等待服務(wù)器推送來數(shù)據(jù)再關(guān)閉,可以采用HTTP長輪詢和XHR長輪詢兩種方式:
(1). HTTP 和JSONP方式的長輪詢
把 script 標(biāo)簽附加到頁面上以讓腳本執(zhí)行。服務(wù)器會掛起連接直到有事件發(fā)生,接著把腳本內(nèi)容發(fā)送回瀏覽器,然后重新打開另一個 script 標(biāo)簽來獲取下一個事件,從而實(shí)現(xiàn)長輪詢的模型。
(2).XHR長輪詢
這種方式是使用比較多的長輪詢模式。
客戶端打開一個到服務(wù)器端的 AJAX 請求然后等待響應(yīng);服務(wù)器端需要一些特定的功能來允許請求被掛起,只要一有事件發(fā)生,服務(wù)器端就會在掛起的請求中送回響應(yīng)并關(guān)閉該請求。客戶端 JavaScript 響應(yīng)處理函數(shù)會在處理完服務(wù)器返回的信息后,再次發(fā)出請求,重新建立連接;如此循環(huán)。
現(xiàn)在瀏覽器已經(jīng)支持CROS的跨域方式請求,因此HTTP和JSONP的長輪詢方式是慢慢被淘汰的一種技術(shù),建議采用XHR長輪詢。
優(yōu)點(diǎn)
客戶端很容易實(shí)現(xiàn)良好的錯誤處理系統(tǒng)和超時管理,實(shí)現(xiàn)成本與Ajax輪詢的方式類似。
缺點(diǎn)
需要服務(wù)器端有特殊的功能來臨時掛起連接。當(dāng)客戶端發(fā)起的連接較多時,服務(wù)器端會長期保持多個連接,具有一定的風(fēng)險。
- >>在這里簡單的說明下長輪詢,長連接的概念
- 輪詢:客戶端定時向服務(wù)器發(fā)送Ajax請求,服務(wù)器接到請求后馬上返回響應(yīng)信息并關(guān)閉連接。優(yōu)點(diǎn):后端程序編寫比較容易。
- 缺點(diǎn):請求中有大半是無用,浪費(fèi)帶寬和服務(wù)器資源。
- 實(shí)例:適于小型應(yīng)用。
- ?
- 長輪詢:客戶端向服務(wù)器發(fā)送Ajax請求,服務(wù)器接到請求后hold住連接,直到有新消息才返回響應(yīng)信息并關(guān)閉連接,客戶端處理完響應(yīng)信息后再向服務(wù)器發(fā)送新的請求。
- 優(yōu)點(diǎn):在無消息的情況下不會頻繁的請求。
- 缺點(diǎn):服務(wù)器hold連接會消耗資源。
- 實(shí)例:WebQQ、Hi網(wǎng)頁版、Facebook IM。
- ?
- 另外,對于長連接和socket連接也有區(qū)分:
- ?
- 長連接:在頁面里嵌入一個隱蔵iframe,將這個隱蔵iframe的src屬性設(shè)為對一個長連接的請求,服務(wù)器端就能源源不斷地往客戶端輸入數(shù)據(jù)。
- 優(yōu)點(diǎn):消息即時到達(dá),不發(fā)無用請求。
- 缺點(diǎn):服務(wù)器維護(hù)一個長連接會增加開銷。
- 實(shí)例:Gmail聊天
- ?
- Flash Socket:在頁面中內(nèi)嵌入一個使用了Socket類的 Flash 程序JavaScript通過調(diào)用此Flash程序提供的Socket接口與服務(wù)器端的Socket接口進(jìn)行通信,JavaScript在收到服務(wù)器端傳送的信息后控制頁面的顯示。
- 優(yōu)點(diǎn):實(shí)現(xiàn)真正的即時通信,而不是偽即時。
- 缺點(diǎn):客戶端必須安裝Flash插件;非HTTP協(xié)議,無法自動穿越防火墻。
- 實(shí)例:網(wǎng)絡(luò)互動游戲。
2.?基于 Iframe 及 htmlfile 的流(streaming)方式
iframe 是很早就存在的一種 HTML 標(biāo)記, 通過在 HTML 頁面里嵌入一個隱蔵幀,然后將這個隱蔵幀的 SRC 屬性設(shè)為對一個長連接的請求,服務(wù)器端就能源源不斷地往客戶端輸入數(shù)據(jù)。
基于流方式的服務(wù)器推模型
?
?
Comet的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):?實(shí)時性好(消息延時小);性能好(能支持大量用戶)缺點(diǎn):?長期占用連接,喪失了無狀態(tài)高并發(fā)的特點(diǎn)。
Comet實(shí)現(xiàn)框架
1. Dojo CometD?——?http://cometdproject.dojotoolkit.org/
2. DWR?——?http://directwebremoting.org/dwr/index.html
3. ICEfaces?——?http://www.icefaces.org/main/home/
4. GlassFish Grizzly?——?https://grizzly.dev.java.net/
CometD?目前實(shí)現(xiàn)?Comet?比較成熟,?DWR?弱一些。?ICEfaces?更商業(yè)化,實(shí)現(xiàn)得很成熟。?Grizzly?是基于GlassFish?,也很成熟。CometD, DWR?開源性好。
Comet實(shí)現(xiàn)要點(diǎn)
不要在同一客戶端同時使用超過兩個的 HTTP 長連接
我們使用 IE 下載文件時會有這樣的體驗(yàn),從同一個 Web 服務(wù)器下載文件,最多只能有兩個文件同時被下載。第三個文件的下載會被阻塞,直到前面下載的文件下載完畢。這是因?yàn)?HTTP 1.1 規(guī)范中規(guī)定,客戶端不應(yīng)該與服務(wù)器端建立超過兩個的 HTTP 連接, 新的連接會被阻塞。而 IE 在實(shí)現(xiàn)中嚴(yán)格遵守了這種規(guī)定。
HTTP 1.1 對兩個長連接的限制,會對使用了長連接的 Web 應(yīng)用帶來如下現(xiàn)象:在客戶端如果打開超過兩個的 IE 窗口去訪問同一個使用了長連接的 Web 服務(wù)器,第三個 IE 窗口的 HTTP 請求被前兩個窗口的長連接阻塞。
所以在開發(fā)長連接的應(yīng)用時, 必須注意在使用了多個 frame 的頁面中,不要為每個 frame 的頁面都建立一個 HTTP 長連接,這樣會阻塞其它的 HTTP 請求,在設(shè)計上考慮讓多個 frame 的更新共用一個長連接。
服務(wù)器端的性能和可擴(kuò)展性
一般 Web 服務(wù)器會為每個連接創(chuàng)建一個線程,如果在大型的商業(yè)應(yīng)用中使用 Comet,服務(wù)器端需要維護(hù)大量并發(fā)的長連接。在這種應(yīng)用背景下,服務(wù)器端需要考慮負(fù)載均衡和集群技術(shù);或是在服務(wù)器端為長連接作一些改進(jìn)。
應(yīng)用和技術(shù)的發(fā)展總是帶來新的需求,從而推動新技術(shù)的發(fā)展。HTTP 1.1 與 1.0 規(guī)范有一個很大的不同:1.0 規(guī)范下服務(wù)器在處理完每個 Get/Post 請求后會關(guān)閉套接口連接; 而 1.1 規(guī)范下服務(wù)器會保持這個連接,在處理兩個請求的間隔時間里,這個連接處于空閑狀態(tài)。 Java 1.4 引入了支持異步 IO 的 java.nio 包。當(dāng)連接處于空閑時,為這個連接分配的線程資源會返還到線程池,可以供新的連接使用;當(dāng)原來處于空閑的連接的客戶發(fā)出新的請求,會從線程池里分配一個線程資源處理這個請求。 這種技術(shù)在連接處于空閑的機(jī)率較高、并發(fā)連接數(shù)目很多的場景下對于降低服務(wù)器的資源負(fù)載非常有效。
但是 AJAX 的應(yīng)用使請求的出現(xiàn)變得頻繁,而 Comet 則會長時間占用一個連接,上述的服務(wù)器模型在新的應(yīng)用背景下會變得非常低效,線程池里有限的線程數(shù)甚至可能會阻塞新的連接。Jetty 6 Web 服務(wù)器針對 AJAX、Comet 應(yīng)用的特點(diǎn)進(jìn)行了很多創(chuàng)新的改進(jìn)。
控制信息與數(shù)據(jù)信息使用不同的 HTTP 連接
使用長連接時,存在一個很常見的場景:客戶端網(wǎng)頁需要關(guān)閉,而服務(wù)器端還處在讀取數(shù)據(jù)的堵塞狀態(tài),客戶端需要及時通知服務(wù)器端關(guān)閉數(shù)據(jù)連接。服務(wù)器在收到關(guān)閉請求后首先要從讀取數(shù)據(jù)的阻塞狀態(tài)喚醒,然后釋放為這個客戶端分配的資源,再關(guān)閉連接。
所以在設(shè)計上,我們需要使客戶端的控制請求和數(shù)據(jù)請求使用不同的 HTTP 連接,才能使控制請求不會被阻塞。
在實(shí)現(xiàn)上,如果是基于 iframe 流方式的長連接,客戶端頁面需要使用兩個 iframe,一個是控制幀,用于往服務(wù)器端發(fā)送控制請求,控制請求能很快收到響應(yīng),不會被堵塞;一個是顯示幀,用于往服務(wù)器端發(fā)送長連接請求。如果是基于 AJAX 的長輪詢方式,客戶端可以異步地發(fā)出一個 XMLHttpRequest 請求,通知服務(wù)器端關(guān)閉數(shù)據(jù)連接。
在客戶和服務(wù)器之間保持“心跳”信息
在瀏覽器與服務(wù)器之間維持一個長連接會為通信帶來一些不確定性:因?yàn)閿?shù)據(jù)傳輸是隨機(jī)的,客戶端不知道何時服務(wù)器才有數(shù)據(jù)傳送。服務(wù)器端需要確保當(dāng)客戶端不再工作時,釋放為這個客戶端分配的資源,防止內(nèi)存泄漏。因此需要一種機(jī)制使雙方知道大家都在正常運(yùn)行。在實(shí)現(xiàn)上:
- 服務(wù)器端在阻塞讀時會設(shè)置一個時限,超時后阻塞讀調(diào)用會返回,同時發(fā)給客戶端沒有新數(shù)據(jù)到達(dá)的心跳信息。此時如果客戶端已經(jīng)關(guān)閉,服務(wù)器往通道寫數(shù)據(jù)會出現(xiàn)異常,服務(wù)器端就會及時釋放為這個客戶端分配的資源。
- 如果客戶端使用的是基于 AJAX 的長輪詢方式;服務(wù)器端返回數(shù)據(jù)、關(guān)閉連接后,經(jīng)過某個時限沒有收到客戶端的再次請求,會認(rèn)為客戶端不能正常工作,會釋放為這個客戶端分配、維護(hù)的資源。
- 當(dāng)服務(wù)器處理信息出現(xiàn)異常情況,需要發(fā)送錯誤信息通知客戶端,同時釋放資源、關(guān)閉連接。
三,websocket方式
?WebSocket是HTML5開始提供的一種在單個 TCP 連接上進(jìn)行全雙工通訊的協(xié)議。WebSocket通訊協(xié)議于2011年被IETF定為標(biāo)準(zhǔn)RFC 6455,WebSocketAPI被W3C定為標(biāo)準(zhǔn)。在WebSocket API中,瀏覽器和服務(wù)器只需要做一個握手的動作,然后,瀏覽器和服務(wù)器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據(jù)互相傳送。
?
?
?由于websocket技術(shù)要說明白的話所需要的篇幅不小,所以會在之后的單獨(dú)文章中介紹下websocket的使用方式,這里就不做詳細(xì)的說明了。
總結(jié)
根據(jù)以上技術(shù)的優(yōu)缺點(diǎn)和具體業(yè)務(wù)需要,可以選擇合適的技術(shù)進(jìn)行應(yīng)用。
轉(zhuǎn)載于:https://www.cnblogs.com/jiangzhaowei/p/9881104.html
總結(jié)
以上是生活随笔為你收集整理的服务器 主动 推送 客户端浏览器 消息***的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript闭包函数箭头函数调用
- 下一篇: 爱上一起野马是什么歌呢?