Http被設計成了一個單向的通信的協議,即客戶端發起一個request,然后服務器回應一個response。這讓服務器很為惱火:我特么才是老大,我居然不能給小弟發消息。。。
輪詢
老大發火了,小弟們自然不能無動於衷,為了能及時獲得老大的消息,小弟們只好每隔一段時間跑去老大那里問問,有沒有新的指示發出。這便是最早實現實時獲得服務器數據的技術輪詢(Polling)。
客戶端通過ajax不停去向服務器獲得數據,檢查是否有新的數據更新。這種使用輪詢實現一種偽實時的狀態很容易,但效率偏低,一般而言,這種實時獲得的數據,本身數據量不是非常大,而通過這種反復地發起request的方式,往往造成的可能是http的header信息比數據本身還多,而且大多數時候獲得的數據都是重復無用的。(據說最早還有通過不斷刷新客戶端頁面,來實現web實時通信的情況~ 我想應該木有哪個客戶會受得了這種體驗。)
Comet
“不值啊!咱哥幾個每天跑來跑去。拿到的都是一堆沒用的數據。”
於是大家坐在一起想,有什么好辦法能不用老是跑腿又可以獲得新的信息及時行動呢?小的們靈機一動,下次我們跑去老大那里等着,等他老人家下了命令再回來。這就是基於 AJAX 的長輪詢(long-polling)方式實現的一種comet方式。因為ajax的調用是異步的,我們可以在頁面加載完畢之后,發起一個request請求,服務器端會阻塞request直到有數據傳遞或超時(timeout)才返回。客戶端處理完服務器返回的信息后,再次發出請求,重新建立連接。這樣周而復始。
基於 AJAX 的long-polling
另外還有一種comet模型,他的名字玄乎比長輪詢邪乎的多。。。叫The forever iframe technique。這名兒聽起來就高大上很多。其實就是在頁面中隱藏一個iframe標簽,然后將這個iframe的 SRC 屬性設為對一個長連接的請求,服務器端就能源源不斷地往客戶端輸入數據。但是這種方法有一個很明顯的問題,各個瀏覽器會一直顯示頁面加載沒有完成,如果用戶是個強迫症,他一定會分分鍾關掉頁面的。TAT……
forever iframe技術
不管怎么樣comet技術第一次實現了真正的實時通信,而且能支持大量用戶,小的們從此總是能准確地獲得老大的消息了。但是comet不會是一個沒有副作用的解決方案,由於長期占用連接,讓web喪失了無狀態高並發的特點,大量消耗了服務器帶寬和資源。
WebSocket登場
“跑來跑去真是麻煩誒~http腫么這么麻煩呀。咱們和老大之間整個新協議吧。”
這個想法在小弟們中炸開了鍋!!! 在大家的千呼萬喚中,WebSocket協議登場了。哈哈哈哈哈~讓我來拯救各位吧~~~~
WebSocket協議是HTML5定義的一種新協議,它實現了瀏覽器與服務器全雙工通信(full-duplex)。通過瀏覽器發出websocket連線請求,然后服務器發出回應,建立一個聯系的通道。小的們只用發個信息問老大:“首長好~”,老大回一個信兒:“同志們辛苦了!”這樣握手(handshaking)就完成了,websocket連線完成,通過websocket,我們可以完成真正的實時通信了。
websocket允許通過JavaScript建立與遠程服務器的連接,從而實現客戶端與服務器間雙向的通信。在websocket中有兩個方法:
1、send() 向遠程服務器發送數據
2、close() 關閉該websocket鏈接
websocket同時還定義了幾個監聽函數
1、onopen 當網絡連接建立時觸發該事件
2、onerror 當網絡發生錯誤時觸發該事件
3、onclose 當websocket被關閉時觸發該事件
4、onmessage 當websocket接收到服務器發來的消息的時觸發的事件,也是通信中最重要的一個監聽事件。
websocket還定義了一個readyState屬性,這個屬性可以返回websocket所處的狀態:
1、CONNECTING(0) websocket正嘗試與服務器建立連接
2、OPEN(1) websocket與服務器已經建立連接
3、CLOSING(2) websocket正在關閉與服務器的連接
4、CLOSED(3) websocket已經關閉了與服務器的連接
websocket的url開頭是ws,如果需要ssl加密可以使用wss,當我們調用websocket的構造方法構建一個websocket對象(new WebSocket(url))的之后,就可以進行即時通信了。
哈哈哈哈哈哈~老大通過websocket發話了:晚上請吃飯!
小弟們趕緊行動起來~
總結
相比comet技術,websocket不僅節約了header的問題(websocket的head信息只有短短的2個字節)。更加重要的是是通信的穩定性,comet在遇到網絡問題之后,想要在不刷新頁面的情況下恢復通信,非常困難,而websocket中提供了onclose函數來處理斷開網絡后的情況,這為我們與服務器的通信提供了可靠的保障。在github上有一個js庫(https://github.com/joewalnes/reconnecting-websocket)就是通過這種方式來處理websocket斷網重連。
websocket看起來廣泛實現只是時間問題了,當然這么好用的websocket也不是沒有它的問題,websocket目前來看最大的問題是瀏覽器的支持(幸好大部分的服務器軟件在比較新的版本中都已經支持了websocket),ie直到10才開始支持這種協議,而且每個瀏覽器最近在升級瀏覽器的時候,都會對websocket做出細微的調整。而且,想象你打開一個頁面,當這個頁面打開websocket連接並且執行一個內部IP地址的端口掃描,如果端口掃描發現了內部網絡上發現了一個開啟的80端口,一個隧道就可能通過你的瀏覽器建立。這樣做很可能最終繞過防火牆,並且允許訪問內部內容。所以安全問題,也是websocket現在面臨的一大隱患。