一次看到 ws:// 和 wss:// 時候,感覺好高級啊,還有這種協議。
WebSocket是在2008年6月誕生的1。經由IEFT標準化后,2009年chrome 4第一個提供了該標準支持,并默認啟用。于2011年由IEFT標準化為RFC 6455。
現在的瀏覽器均已支持該標準。
思考一下我們經常遇到的一種需求場景,要求在某個網頁下,網頁的內容可以實時更新。
這種情況下,最大眾化的方式就是輪詢接口了,即通過定時器,定時請求接口,獲取到最新的信息后,將內容更新到頁面中,如下:
setInterval(()=> {
queryAPI().then(()=> update());
}, 1000);
但是我們知道,這種定時器的延時并不是很精確,而且加上接口的請求時延,實際時間可能不止代碼中所預先設定的時間長度,所以這種實時更新是偽實時更新。
除此之外,還有一點可能會經常遇到,即,我們更新信息并總是要更新整個頁面上所有可以看到的信息,我們更關注一些經常變化的信息,比如狀態,狀態的信息可能大小只有幾個字節,但是我們輪詢接口拿到的信息卻是這個頁面的所有信息,大小自然不只幾個字節,但是除狀態以外的信息都可以視作是冗余的。
我們實際只需要一個字段,而且即使后端提供只返回狀態的接口,但實際在一個請求中還要計算ip報文頭的大小,依舊是很占用帶寬的。
輪詢這種解決方案目前依舊是非常流行,最新的輪詢技術是Comet,這種技術雖然可以實現雙向通信,但仍然需要反復發出請求。而且在Comet中普遍采用的HTTP長連接也會消耗服務器資源2。
了解網絡的都知道,數據傳輸分為單工、半雙工、全雙工三種工作模式。
Websocket是基于TCP的,使用全雙工通信模式的協議,他使得客戶端和服務端之間的數據交換變得更簡單。而且,作為一個工作在全雙工模式下的協議,服務端可以在建立連接后隨時向客戶端推送消息。
由于協議是基于TCP的,所以websocket也是需要建連和關閉連接的,但要注意的是,一般在websocket的握手通常指的是:客戶端發送一個http請求到服務端,服務端響應后標志這個鏈接建立起來。而不是指tcp的三次握手。
另外在RFC 6455 1.1節「Background」中介紹:WebSocket通過HTTP端口的80和443進行工作,并支持HTTP代理和中介。
原文:it is designed to work over HTTP ports 80 and 443 as well as to support HTTP proxies and intermediaries
為了實現和HTTP的兼容性,WebSocket握手使用HTTP的Upgrade頭將HTTP協議轉換成Websocket協議。
作為一種協議,websocket自然也是有其用于協議控制的頭部信息的,但是相對于HTTP請求每次都要帶上完整的頭部信息,傳輸數據時,websocket數據包的頭部信息就相對較小,從而降低了控制開銷。
相對于前文所提到的輪詢接口,websocket可以做到服務端直接向客戶端傳輸數據,省去了客戶端發起請求的步驟,同時沒有間隔時間,只要服務端內容變化,就可以告知客戶端,實時性上有了很大的提高。
WebSocket使用十分簡單,只需要關注以下API:
使用 new WebSocket(xxx) 創建對象時,會同時建立與服務器的連接
分別對應連接成功、失敗時的回調,這里可以做一些初始化、銷毀的工作
實際處理數據是用的該函數
在數據處理完成后,需要移除回調函數,不然可能會影響到其他地方的處理
const ws=new WebSocket('ws://sdf.com');
function handleData(evt) {
// handle server data.
}
ws.onmessage=handleData;
ws.addEventListener('message', handleData);
主動向服務端發送消息,可以通過send和onmessage進行數據互動,如:
ws.send('list');
ws.onmessage=evt=> {
const data=evt.data;
if (data==='hello') {
console.log('world');
return ;
}
try {
const obj=JSON.parse(data);
switch (obj.type) {
case 'list':
// do something.
}
} catch (ex) {}
}
關閉連接
Node服務端的實現,這個就參考相關的庫吧,比較復雜。
http協議至今,主要經歷了三個版本。
來源:https://www.cnblogs.com/keepsmart/p/16007094.html
(1)建立在 TCP 協議之上,服務器端的實現比較容易。
(2)與 HTTP 協議有著良好的兼容性。默認端口也是80和443,并且握手階段采用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。
(3)數據格式比較輕量,性能開銷小,通信高效。
(4)可以發送文本,也可以發送二進制數據(blob對象或Arraybuffer對象)
(5)收到的數據類型 可以使用binaryType 指定, 顯示指定收到的二進制數據類型
(6)沒有同源限制,客戶端可以與任意服務器通信。
(7)協議標識符是ws(握手http)(如果加密,則為wss(tcp +TLS)),服務器網址就是 URL。
WebSocket對象提供了用于創建和管理WebSocket 連接,以及可以通過該連接發送和接收數據的 API。
使用 WebSocket() 構造函數來構造一個 WebSocket 。
一種無狀態的、應用層的、以請求/應答方式運行的協議,它使用可擴展的語義和自描述消息格式,與基于網絡的超文本信息系統靈活的互動.
Data: 消息負載。 如果消息為純文本,直接顯示。 二進制操作嗎顯示操作碼名稱和代碼(Continuation Frame、 Binanry Frame、 Connection Close Frame、 Ping Frame或者Pong Frame)
Length: 消息負載的長度 以字節為單位
Time: 收到或者發送的時間。
1、實時性與可伸縮性。 犧牲了簡單性。
2、網絡效率與無狀態: 請求1基于請求2 犧牲了簡單性與可見性
可以使用Access-Control-Allow-Origin 等頭部
ini
復制代碼
ws-frame=frame-fin ; 1 bit in length frame-rsv1 ; 1 bit in length frame-rsv2 ; 1 bit in length frame-rsv3 ; 1 bit in length frame-opcode ; 4 bits in length frame-masked ; 1 bit in length frame-payload-length ; 3 種長度 [ frame-masking-key ] ; 32 bits in length frame-payload-data ; n*8 bits in ; length, where ; n >=0
紅色: 2 字節必然存在的幀首部
RSV1/RSV2/RSV3:默認為 0,僅當使用 extension 擴展時,由擴展決定其值
1、ws-uri: ws://[host][:port][path][?query]
端口port默認 80
2、wss-uri: wss://[host][:port][path][?query] 端口port 默認443
host、port 主機端口
schema: 是否基于SSL
訪問的資源:uri
握手隨機數:Sec-WebSocket-Key
選擇的子協議:Sec-WebSocket-Protocol
擴展協議:Sec-WebSocket-Extensions
CORS:Origin
請求中的 Sec-WebSocket-Key 隨機數
Sec-WebSocket-Key: A1EEou7Nnq6+BBZoAZqWlg==
響應中的 Sec-WebSocket-Accept 證明值
GUID(RFC4122):258EAFA5-E914-47DA-95CA-C5AB0DC85B11
? 值構造規則:BASE64(SHA1(Sec-WebSocket-Key + GUID))
? 拼接值:A1EEou7Nnq6+BBZoAZqWlg==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
? SHA1 值:713f15ece2218612fcadb1598281a35380d1790f
? BASE 64 值:cT8V7OIhhhL8rbFZgoGjU4DReQ8=
? 最終頭部:Sec-WebSocket-Accept: cT8V7OIhhhL8rbFZgoGjU4DReQ8=
作者:LHDIYU
鏈接:https://juejin.cn/post/6989539483695710215
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
WebSocket 作為一種基于 TCP 協議的實時通信協議,為前端應用提供了強大的雙向通信能力。本文將深入探討前端 WebSocket 的相關問題,包括協議區別、用法、關鍵技術點等。
WebSocket 是一種實時雙向通信協議,與 HTTP 協議相比,有以下幾個主要區別:
WebSocket 相對于傳統的 HTTP 請求具有以下優勢:
WebSocket 的適用場景包括實時聊天應用、股票行情推送、實時協作編輯、多人游戲、實時數據監控等需要實時雙向通信的場景。
WebSocket 的連接建立過程包括以下步驟:
WebSocket 提供了以下幾種事件:
這些事件可以通過設置對應的事件處理函數來處理不同的連接狀態和數據傳輸。
在瀏覽器端,可以使用 JavaScript 中的 WebSocket 對象來創建和使用 WebSocket。示例代碼如下:
const socket=new WebSocket('wss://example.com/socket');
其中,new WebSocket() 通過傳入服務器的 WebSocket URL 來創建一個 WebSocket 對象。然后可以通過設置事件處理函數來處理 WebSocket 的事件,例如:
socket.onopen=function(event) {
console.log('WebSocket 連接已打開');
};
socket.onmessage=function(event) {
const message=event.data;
console.log('接收到消息:', message);
};
socket.onerror=function(error) {
console.error('WebSocket 錯誤:', error);
};
socket.onclose=function(event) {
console.log('WebSocket 連接已關閉');
};
在連接建立成功后,可以使用 send() 方法發送消息到服務器,例如:
socket.send('Hello, server!');
通過 WebSocket 的 send() 方法可以向服務器發送消息,例如:
socket.send('Hello, server!');
接收到的消息可以在 onmessage 事件處理函數中進行處理,例如:
socket.onmessage=function(event) {
const message=event.data;
console.log('接收到消息:', message);
};
WebSocket 除了發送和接收文本消息外,還支持發送和接收二進制數據。對于發送二進制數據,可以使用 send() 方法傳遞一個 ArrayBuffer 或 Blob 對象,例如:
const buffer=new ArrayBuffer(4);
const view=new DataView(buffer);
view.setUint32(0, 1234);
socket.send(buffer);
在接收二進制數據時,可以通過 event.data 獲取到 ArrayBuffer 對象,然后進行處理。
WebSocket 在出現錯誤時會觸發 error 事件,可以通過設置 onerror 事件處理函數來處理錯誤,例如:
socket.onerror=function(error) {
console.error('WebSocket 錯誤:', error);
};
當 WebSocket 連接關閉時,會觸發 close 事件,可以通過設置 onclose 事件處理函數來執行一些清理操作或重新連接等操作,例如:
socket.onclose=function(event) {
console.log('WebSocket 連接已關閉');
};
可以通過調用 close() 方法來顯式地關閉 WebSocket 連接,例如:
socket.close();
WebSocket 支持通過 wss:// 前綴建立加密的安全連接,使用 TLS/SSL 加密通信,確保數據的安全性。在使用加密連接時,服務器需要配置相應的證書。
對于跨域問題,WebSocket 遵循同源策略,只能與同源的服務器建立連接。如果需要與不同域的服務器通信,可以使用 CORS(跨域資源共享)來進行跨域訪問控制。
在實際應用中,可以通過監聽 open、error 和 close 事件來處理連接狀態的變化。當連接關閉時,可以根據需要執行重連機制,例如使用指數退避算法進行重連,以確保連接的穩定性和可靠性。
為了優化 WebSocket 的性能,可以考慮以下幾個方面:
WebSocket 和長輪詢都可以實現實時通信,但它們具有不同的特點和適用場景。
WebSocket 的優點:
WebSocket 的缺點:
長輪詢的優點:
長輪詢的缺點:
根據具體需求和場景,選擇合適的方案來實現實時通信。如果需要更高的實時性和較低的網絡開銷,WebSocket 是更好的選擇。如果兼容性要求較高或者對實時性要求不高,可以考慮使用長輪詢。
作者:囂張農民
鏈接:https://juejin.cn/post/7288963909591138344
*請認真填寫需求信息,我們會在24小時內與您取得聯系。