WebSocket 是一種讓瀏覽器與伺服器進行一段互動通訊的技術。可以直接進行即時的通訊而不用一直輪循(Rolling)-擷自MDN web docs。為了更清楚瞭解websocket,紀錄一下它發展的過程還有背後使用的技術。
關於Real-time
web建立在client和server身上,client的工作就是向server請求資料;server的工作則是去回復每一個client的請求(如下圖)。這樣的一來一往的模式持續了多年,2005年隨著AJAX的出現,於是大家開始摸索client-server雙向溝通的可能性。
Source:WebSockets - A Conceptual Deep-Dive
web application開始發展快速,最大的挑戰在於HTTP model of client initiated transactions! 於是為了克服,不同的方法開始陸續出現像是long-polling-保持HTTP的連線開啟,直到server有data可以傳給client。
出現的解決方式大都是carry the overhead of HTTP.每次送出一個請求,伴隨著一堆header、cookie的資料要傳給server。
實現Real-time
大致上有幾種方式:
- Long/short polling (Client pull)
- WebSocket (Server push)
- Server-Sent Events (Server push)
-
client pull- client端週期性的向server詢問,update特定資料
-
server push- server端主動告訴client有資料要更新
Source:Polling vs SSE vs WebSocket— How to choose the right one
1. Polling(輪詢)
Polling is a technique by which the client asking the server for new data regularly.
分成兩種short polling/ long polling
Short Polling
- short polling is AJAX-based timer
- A client makes XHR(XMLHttpRequest)/Ajax requests to server repeatedly at some regular interval to check for new data.
- 週期性的一直發出Request
- 易實作、無跨瀏覽器問題
- 效率差、浪費頻寬
Long Polling(comet的改良進化)
- long polling is based on Comet(當server有event發生,server傳送data給client)
- Long polling is technique where the server elects to hold a client connection open for as long as possible, delivering a response only after data becomes available or timeout threshold has been reached.
- 發出一個長時間的等待Request,當有資料或是timeout時,再發一個新的Request
Source:WebSockets - A Conceptual Deep-Dive
</br>
加映:關於AJAX(Asynchronous Javascript and XML)
與傳統網站不同在於,Browser(Web page)自行建立Request送給Server,並處理傳來的Response。Ajax模組提供一個中間層(Ajax Engine)來控制溝通過程,Ajax engine即向server請求資訊時要呼叫的Javascript物件。
使用方式
-
XMLHttpRequest(舊式寫法)
-
取得browser提供的XMLHttpRequest物件(XHR)
-
不限接受XML類型的資料,亦支援HTTP外的協定(ex:file, ftp)
-
XMLHttpRequest會回傳每次的狀態(readystate):
-
//產生XMLHttpRequest物件實體 const xhr = new XMLHttpRequest(); // readystate狀態 // 0-已產生xhr,還沒呼叫open // 1-已open,尚未傳送出去 // 2-已send // 3-loading-解析內容 // 4-已收到完整資料 // 每次變化都會觸發readystatechange事件,造成readystate值改變 xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { document.write(xhttp.responseText) } }; // open('method(get:讀取資料/post:傳送資料到伺服器)',url(要連的資源或檔案),async(true-同步;false-非同步) xhr.open('GET',"./xxx.txt",true); // true-非同步,不會痴痴等待 // false-同步,等資料回來,才會繼續執行 xhr.send(null);
-
-
利用jQuery的ajax
-
$.ajax(url,[settings])
-
jQuery.ajax()提供的callback:依序為1.beforeSend-> 2.success/error -> 3. complete
-
$.ajax({ url: '', // 請求要送往的url位置orxxx.php type: 'post', // post/get data: { }, // 輸入的資料(Obj,string or array)-送給server的data dataType, // 期望server傳回的資料格式 error: function (xhr) { }, // 錯誤->執行的函數 success: function (response) { }// 成功->要執行的函數 async:true, // 同步與否 });
-
加映:關於Comet
如同comet單字解釋一樣,彗星!使Request像彗星,拉的很長,於是可以不結束連線,讓server持續回傳data給client。作法有兩種:
- Ajax實現comet
- iframe實現comet
後來出現改良的comet,發出一個長時間等待的Request,當server有資料時,立即斷掉在發出一個新的Request。作法也有兩種:
-
Long Polling
browser發出一個request,server讓request持續開啟一段時間。在這段期間內server有資料就會回傳,如果沒有等到時間一到,server就會結束request,browser知道request被結束了,又會再發出一個新的request。
-
Streaming
讓server和client建立一個持續的連線,為了不中斷連線,server會每隔一段時間就發送Response給client,確保連線不中斷,server將資料傳入iframe,讓javascript去負責頁面的更新
有些網站會這樣描述Polling:出遠門時,小孩子會一直問到了嗎到了嗎,等同發送一個長時間等待的Request,當server端有data時,就發送新的request。
javascript 相關http的library像是jQuery or Axios可以使用。而利用setTimeout & 遞迴的方式(搭配ajax)一樣可以達到Long-Polling。
2. WebSocket
定義在HTML5中,提供了browser和server進行雙向通訊的技術-WebSocket,當連線完成,client端可以隨時send訊息給server,server也可以隨時推送訊息給client端。雙向且全雙工(bi-direction and full-duplex),特別要注意的是各家瀏覽器的支援程度。
Source:WebSockets - A Conceptual Deep-Dive
3. Server-Sent Events(SSE)
server端推送事件,透過HTTP協定,允許server向client發送數據的HTML5技術。如果client端不太需要傳送資料給server,只是負責接收資料,就可以考慮使用SSR單向的傳輸方式。
Review-再回到Websocket
不只是應用在我們常聽到的即時聊天室上,其他像是要重複性的呼叫RESTful API、需要長時間才會回傳值的呼叫或是一個live data必須即時的顯示給使用者。
-
client傳送一個HTTP請求給server
-
header中的Upgrade代表此client希望建立一個websocket連線
GET ws://websocket.example.com/ HTTP/1.1 Origin: http://example.com Connection: Upgrade Host: websocket.example.com Upgrade: websocket
-
如果server支援websocket協議,會回傳包含Upgrade header的response
HTTP/1.1 101 WebSocket Protocol Handshake Date: Wed, 16 Oct 2013 10:07:34 GMT Connection: Upgrade Upgrade: webSocket
於是handshake完成,而最初的HTTP連線被websocket連線取代(TCP/IP connection)。
Source:http://jar.fyicenter.com/
小結
蠻幸運的在面試中,收到一個task實作,而有機會開始了解websocket,整理這篇的過程中有太多可以延伸的東西,**TCP? UDP? 網路層? ** 或是各種Real-time的實作code? 各大家產品是採用哪種方式解決Real-time?
期待再一點一點補齊基礎!!
延伸閱讀&參考圖文
獲得實時更新的方法-Polling, Comet, Long Polling, WebSocket
5 ways to build real-time apps with Javascript
Polling vs SSE vs WebSocket— How to choose the right one
WebSocket 通訊協定簡介:比較 Polling、Long-Polling 與 Streaming 的運作原理