背景
前面在做即時通訊相關業務的時候發現了一個有趣的點,即時通訊的實現方式是怎樣的,仔細翻閱了一波文檔發現在騰訊IM中他們使用的是普通輪詢機制,在網易IM中他們使用的是可配置的(websocket、xhr-polling、flashsocket )三選一模式
探索點
基於上面的背景之下,想對websocket、xhr-polling、flashsocket三者進行一波學習了解,以及聯想到早前使用comet實現單點登錄的原理是什么,數據同步的發展歷程是怎樣的
發展歷程
數據同步可以說應用場景十分普遍的一個需求,需要實時從服務端更新數據到客戶端,隨着技術的發展,歷史長河中也出現了不同版本的實現方式
傳統輪詢
在web早期,並不是通過ajax請求去來刷新數據的,需要實現數據的同步都是通過設置mate來刷新實現,指示瀏覽器在指定秒數之后重新裝載頁面,從而支持簡陋的輪詢(polling)
例如,在HTML文件中加入<META HTTP-RQUIV="Refresh" CONTENT=10>,就是HTTP頭標告知瀏覽器每十秒重載入一次文檔
缺陷:
-
十分糟糕的用戶體驗,需要重新渲染DOM結構和數據
-
對服務器來說要命,以及寬帶資源的浪費
AJAX輪詢
ajax輪詢機制可以說有着輝煌的歷史,至今依舊很多地方使用着,用它實現數據同步的方式可簡單分為兩種
-
普通輪詢(polling)
使用setIntervel模式,每隔一段時間就去請求一次服務器,查詢數據是否有改變,從而進行增量式的更新
但是間隔多長時間去查詢成了問題,因為性能和即時性造成了嚴重的反比關系,間隔太短,連續不斷的請求會沖垮服務器,間隔太長,數據的更新就會出現很高的延遲
優點:
-
使用十分簡單粗暴,不需要服務端做什么配置
-
相對傳統輪詢來說還是降低了寬帶資源的浪費
缺點:
-
對服務器來說依舊有很大的壓力,無法支撐大量用戶
-
及時性較差,可能會有較高的延遲
-
第二次的新數據可能會被第一次的數據覆蓋,雖然幾率很小
-
-
長輪詢(long-polling)
長輪詢是對普通輪詢的升級,普通輪詢對於服務器來說亞歷山大,過多請求直接可能壓爆服務器,因為它並不管服務端是否有新數據啥的,始終隔一段時間就發起請求
基於此,延伸出了長輪詢,方案是在客戶端發起請求后如果服務端沒有新數據需要返回給客戶端,那么服務端將會把此請求掛起,即阻塞此次請求,等有數據需要返回給客戶端時才進行相應,然后關閉此次請求,客服端接收到相應關閉此次請求后將再次發起一個新的請求,如此循環往復,來實現數據到同步
優點:
-
降低了同步延遲
-
可以支撐大量用戶
-
降低了寬帶資源的浪費
-
不會出現數據被覆蓋的情況
缺點:
-
長期占用連接,無狀態高並發功能喪失
-
鏈接中斷幾率不低
-
不能在同一個客戶端開啟超過兩個的http長連接,受http協議限制
-
COMET
comet 有時也稱反向Ajax或服務器端推技術(server-side push),其思想很簡單:將數據直接從服務器推到瀏覽器,而不必等到瀏覽器請求數據,精髓就在於用服務器與javascript來維持瀏覽器的長連接,同時完成服務器端事件的客戶端端響應(客戶端實時響應服務端的同步)
comet是長輪詢的一個應用場景之一,但是comet的實現方式又不止長輪詢一種
另一種實現comet機制:基於iframe及htmlfile流的方式(永久幀),iframe流方式是在頁面中插入一個隱藏的iframe,利用其src屬性在服務器和客戶端之間建立一條長鏈接,服務器向iframe傳輸數據(通常是HTML),內有負責插入信息的JavaScript),來實時更新頁面
優缺點同步長輪詢
FlashSocket
FlashSocket(經由Flash的套接口),它是WebSocket發展過程中的一個過渡產物,在初期的WebSocket並不被所有瀏覽器支持,這些庫通常會提供同樣的官方WebSocket API,但他們是通過把調用委托給一個包含在網站中的隱藏的Flash組件來實現的
優點:
-
FlashSocket透明地提供了WebSocket的功能,即使是在不支持HTML5 WebSocket的瀏覽器上也是如此
缺點:
-
其需要安裝Flash插件
-
要求防火牆的843端口是打開的,這樣Flash組件才能發出HTTP請求來檢索包含了域授權的策略文件
-
如果客戶端處在某個代理服務器的后面的話,到端口843的連接可能會被拒絕
屬於過渡性產品,幾乎已被淘汰
WebSocket
在HTML5中出現的WebSocket是一種比Comet還要新的反向Ajax技術,WebSocket啟用了雙向的全雙工通信信道,許多瀏覽器(Firefox、Google Chrome和Safari)都已對此做了支持。連接是通過一個被稱為WebSocket握手的HTTP請求打開的,其用到了一些特殊的報頭,連接會保持在活動狀態,可以使用JavaScript來寫入和接收數據,就像是在使用一個原始的TCP套接口一樣,而且WebSocket與http協議一樣都是基於TCP來進行數據的傳輸的,屬於對TCP數據傳輸的一種規范,所以它是可靠的協議
WebSocket偉大之處在於服務器和客戶端可以在鏈接期間的任意時刻,相互推送信息,而且並不限於以Ajax或XHR方式通信,因為Ajax技術需要客戶端發起請求,而webSocket服務器和客戶端可以彼此相互推送信息;XHR受到域的限制,而WebSocket允許跨域通信,webSocket URL的起始輸入是ws://或是wss://
const ws = new WebSocket(“ws://echo.websocket.org”) ws.onopen = () => {ws.send(“Test!”) } ws.onmessage = function(evt){console.log(evt.data);ws.close()} ws.onclose = function(evt){console.log(“WebSocketClosed!”)} ws.onerror = function(evt){console.log(“WebSocketError!”)}
優點:
-
WebSocket功能強大、雙向、低延遲,且易於處理錯誤
-
不會像comet長輪詢那樣有許多的連接
-
API容易使用,無需另外的層就可以直接使用
遺留點
-
套接字
-
Ajax與XHR的關系
-
wx傳輸過程