輪詢以及webSocket與socket.io原理
- 2022 年 8 月 10 日
- 筆記
概述:
首先,我們知道,起初的http協議只是為了能夠進行通信而被創造出來(也就是請求-響應的過程)。並沒有雙向通信這一說,後面隨着歷史業務的需求,人們使用輪詢http來解決雙向通信也就是使用xhr或者jsonp的方法進行發送請求到服務端並且進行回調獲取服務端數據
通信的幾個名稱:
單工通訊:既只能客戶端向服務端發送數據或者服務端向客戶端發送數據(如廣播,電視之類的,他可以給你傳播信息,你卻不能給他回應)
半雙工單向通訊:客戶端可以向服務端發送數據,服務端也可以向客戶端發送數據,但是不能同時,只能這一端發送完後另一端才可以進行響應(對講機,他講一句你講一句,但是不能同時講)
全雙工通訊:客戶端可以向服務端發送數據,服務端也可以向客戶端發送數據,可以同時進行(電話,qq聊天等等,可以同時講或者發送消息)
1:輪詢:隔一段時間進行一次查詢或者詢問
輪詢分為長輪詢和短輪詢,長輪詢是基於短輪詢的一個優化結果。
短輪詢:
通過客戶端定期輪詢來詢問服務端是否有新的信息產生,如果有則返回,沒有就不響應,
缺點:也是顯而易見,輪詢間隔大了則信息不夠實時,輪詢間隔過小又會消耗過多的流量,增加服務器的負擔。
長輪詢:
是需要服務端進行更改來進行支持,客戶端向服務端發送請求時,如果此時服務端沒有新的信息產生,並不立刻返回,而是Hold住一段時間等有新的信息或者超時再返回,客戶端收到服務器的應答後繼續輪詢。可以看到長輪詢比短輪詢可以減少大量無用的請求,並且客戶端接收取新消息也會實時不少。減少http請求對性能的優化是很有利的,所以他是短輪詢上的一個優化
缺點:終歸來講還是一個http請求,只是進行了變化而已,而且如果客戶端不請求,服務端有數據的話,也會一直累積在那,不能實現實時的雙向通信
此時的webSocket也就應需而生了
2:webSocket協議原理
webSocket也是基於Tcp協議傳輸層連接的,跟http相同處於協議應用層,而且它還是基於http的握手的,只是是握手的時候會傳輸特定的數據讓協議升級成為webSocket協議
與http與之不同的是webSocket是一個持久化協議,而http協議是一個非持久化協議,也就是http他請求然後響應就結束了,而webSocket會一直保持連接而且一直傳輸數據,直到你將連接斷開
websocket連接過程:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: Y3JJCMbDL1IDUCH9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 20
其中的這倆段代碼就是將http升級為webSocket的關鍵
Upgrade: websocket
Connection: Upgrade
而後面的三行代碼則是一些驗證信息
Sec-WebSocket-Key:瀏覽器隨機生成,用於給服務端使用,如果服務端支持webSocket,服務端會對該數據進行一些處理然後返回給客戶端進行驗證Sec-WebSocket-Protocol:是一個列表,列表中列出客戶端所支持的協議Sec-WebSocket-Version:指定版本
然後服務端就會返回
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
服務端返回這倆段代碼就說明升級成功
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept:對Sec-WebSocket-Key進行處理後的數據。用於證明他是支持升級後的協議的,驗證成功Sec-WebSocket-Protocol:服務端最終選定的協議
做完這些以後這次連接之後就都是webSocket連接了
3:socket.io原理
介紹
首先,socket.io是一個庫,一個基於engine.io協議(封裝了webSocket協議)的庫,在協議上創建了Engine.io引擎,socket.io則是該引擎的應用層框架
它相對比原生webSocket的一些特性
長輪詢回退:如果無法建立webSocket連接,socket.io將會退回到http長輪詢進行連接,這也是為了兼容一些特別老的項目和極少數不支持的瀏覽器(現如今)自動連接:在一些情況下,連接某一方有可能在不知情的情況下斷開,它有一個心跳機制,可以定時去監測是否連接,只要不是客戶端主動關閉連接,socket.io就會在連接出錯後不斷重試以建立連接,服務端數據會進行自動緩衝,直到再次連接,為了防止斷開時間過長,緩衝時間過長,可以利用使用Socket 實例的connected屬性進行處理,或者使用Volatile事件,使服務端丟棄原來的緩衝,只返回最新的數據(官網有該方法,在此就不描述)多路復用:Socket.io允許你在單個共享連接上創建多個namespace,這些namespace擁有單獨的通信通道(room),也可設置單獨的權限驗證,但是可以共享原來的底層連接;例如,如果您想創建一個只有授權用戶才能加入的管理員頻道支持Room功能:room是在namespace下的,舉個例子:namespace如同一片地區,room是這片地區中個房子,socket則是房子中的人,namespace是可以在別的namespace中通信的,但是room只能在該spacename下的room之間進行通信,socket也只能收到該namespace的廣播

socket.io連接過程:
同樣客戶端發起http請求,並帶有
Upgrade: websocket
Connection: Upgrade
服務端返回
"sid":"ab4507c4-d947-4deb-92e4-8a9e34a9f0b2"
"upgrades":["websocket"]
"pingInterval":25000
"pingTimeout":60000}
sid:sid 是本次會話的ID,因為一次連接包含了多個請求,sid 的作用就相當於 SESSION ID。也是客戶端的標識pingInterval:ping的間隔時長pingTimeout:判斷連接超時的時長
當客戶端收到響應之後,scoket.io會根據當前客戶端環境是否支持Websocket。如果支持,則建立一個websocket連接,否則退回到長輪詢進行雙向數據通信。
engine.io協議原理
engine.io的數據分為Packet和Payload,其中 Packet是數據包,有6種類型:
0. open:從服務端發出,標識一個新的傳輸方式已經打開。
close:請求關閉這條傳輸連接,但是它本身並不關閉這個連接。ping:客戶端周期性發送ping,服務端響應pong。pong:服務端發送。message:真實數據upgrade:在轉換(transport)前,engine.io會發送探測包測試新的transport(如websocket)是否可用,如果OK,則客戶端會發送一個upgrade消息給服務端,服務端關閉老的transport然後切換到新的transport。用於升級協議noop:空操作數據包,客戶端收到noop消息會將之前等待暫停的輪詢暫停,用於在接收到一個新的websocket強制一個新的輪詢周期。
4:總結
socket.io可以說是一個很好的工具,無論是用做聊天或者是其他實時的數據通信,在使用時也遇到過一些問題,後面都慢慢解決了



