Websocket的用法及常見應(yīng)用場景
一、什么是Websocket
WebSocket 是一種在單個 TCP 連接上進行 全雙工 通信的協(xié)議,它可以讓客戶端和服務(wù)器之間進行實時的雙向通信。
WebSocket 使用一個長連接,在客戶端和服務(wù)器之間保持持久的連接,從而可以實時地發(fā)送和接收數(shù)據(jù)。
在 WebSocket 中,客戶端和服務(wù)器之間可以互相發(fā)送消息,客戶端可以使用 JavaScript 中的 WebSocket API 發(fā)送消息到服務(wù)器,也可以接收服務(wù)器發(fā)送的消息。
二、Websocket特點
簡單來說,websocket 具有 雙向通信,實時性強,支持二進制,控制開銷 的特點。
1、協(xié)議標識符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是 URL。
2、實時通信,服務(wù)器可以隨時主動給客戶端下發(fā)數(shù)據(jù)。
3、保持連接狀態(tài),Websocket需要先創(chuàng)建連接,所以是一種有狀態(tài)的協(xié)議,之后通信時就可以省略部分狀態(tài)信息。
4、控制開銷,連接創(chuàng)建后,服務(wù)器和客戶端之間交換數(shù)據(jù)時,用于協(xié)議控制的數(shù)據(jù)包頭部相對較小。在不包含擴展的情況下,對于服務(wù)器到客戶端的內(nèi)容,此頭部大小只有2至10字節(jié)(和數(shù)據(jù)包長度有關(guān));對于客戶端到服務(wù)器的內(nèi)容,頭部還需要加上額外的4字節(jié)的掩碼。
5、實現(xiàn)簡單,建立在 TCP 協(xié)議之上,服務(wù)器端的實現(xiàn)比較容易,并且沒有同源限制,客戶端可以與任意服務(wù)器通信。
6、支持二進制傳輸,Websocket定義了二進制幀,可以發(fā)送文本,也可以發(fā)送二進制數(shù)據(jù)。
7、與 HTTP 協(xié)議有著良好的兼容性。默認端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務(wù)器。
8、支持擴展,用戶可以擴展協(xié)議、實現(xiàn)部分自定義的子協(xié)議,如部分瀏覽器支持壓縮等。
三、WebSocket與HTTP的區(qū)別
websocket和http都是基于TCP的應(yīng)用層協(xié)議,使用的也是 80 端口(若運行在 TLS 之上時,默認使用 443 端口)。
其區(qū)別主要就在于連接的性質(zhì)和通信方式。
WebSocket是一種雙向通信的協(xié)議,通過一次握手即可建立持久性的連接,服務(wù)器和客戶端可以隨時發(fā)送和接收數(shù)據(jù)。
而HTTP協(xié)議是一種請求-響應(yīng)模式的協(xié)議,每次通信都需要發(fā)送一條請求并等待服務(wù)器的響應(yīng)。
WebSocket的實時性更好,延遲更低,并且在服務(wù)器和客戶端之間提供雙向的即時通信能力,適用于需要實時數(shù)據(jù)傳輸?shù)膱鼍啊?/p>
四、常見應(yīng)用場景
- 實時聊天:WebSocket能夠提供雙向、實時的通信機制,使得實時聊天應(yīng)用能夠快速、高效地發(fā)送和接收消息,實現(xiàn)即時通信。
- 實時協(xié)作:用于實時協(xié)作工具,如協(xié)同編輯文檔、白板繪畫、團隊任務(wù)管理等,團隊成員可以實時地在同一頁面上進行互動和實時更新。
- 實時數(shù)據(jù)推送:用于實時數(shù)據(jù)推送場景,如股票行情、新聞快訊、實時天氣信息等,服務(wù)器可以實時將數(shù)據(jù)推送給客戶端,確保數(shù)據(jù)的及時性和準確性。
- 多人在線游戲:實時的雙向通信機制,適用于多人在線游戲應(yīng)用,使得游戲服務(wù)器能夠?qū)崟r地將游戲狀態(tài)和玩家行為傳輸給客戶端,實現(xiàn)游戲的實時互動。
- 在線客服:WebSocket可以用于在線客服和客戶支持系統(tǒng),實現(xiàn)實時的客戶溝通和問題解決,提供更好的用戶體驗,減少等待時間。
五、websocket實例

為了建立一個 WebSocket 連接,客戶端瀏覽器首先要向服務(wù)器發(fā)起一個 HTTP 請求,這個請求和通常的 HTTP 請求不同,包含了一些附加頭信息,其中附加頭信息"Upgrade: WebSocket"表明這是一個申請協(xié)議升級的 HTTP 請求,服務(wù)器端解析這些附加的頭信息然后產(chǎn)生應(yīng)答信息返回給客戶端,客戶端和服務(wù)器端的 WebSocket 連接就建立起來了,雙方就可以通過這個連接通道自由的傳遞信息,并且這個連接會持續(xù)存在直到客戶端或者服務(wù)器端的某一方主動的關(guān)閉連接。
1)Websocket事件
- onopen: 客戶端和服務(wù)器建立連接后觸發(fā),被稱為客戶端和服務(wù)器之間的初始握手。如果接收到open, 說明已經(jīng)連接成功,可以進行通信了。
- onmessage: 接收到消息時觸發(fā)。服務(wù)器發(fā)送給客戶端的消息可包括純文本消息,二進制數(shù)據(jù)(Blob消息或者ArrayBuffer消息)。
- onerror: 響應(yīng)意外故障時觸發(fā),在錯誤之后總是會終止連接。
- onclose:連接關(guān)閉時觸發(fā)。一旦連接關(guān)閉后,客戶端和服務(wù)端將不會再進行消息的收發(fā)。也可主動調(diào)用close()方法關(guān)閉連接。
2)Websocket方法
- send() : 在連接成功后關(guān)閉前,發(fā)送消息(onopen后和onclose前才可發(fā)送消息)
參數(shù):
data: 要發(fā)送的數(shù)據(jù),可以是字符串、二進制數(shù)據(jù)或者 Blob 對象。- close() : 關(guān)閉連接
參數(shù):
code(可選): 一個數(shù)字,表示連接關(guān)閉的狀態(tài)碼。常見的狀態(tài)碼有 1000 表示正常關(guān)閉,1001 表示端點離開,等等。reason(可選): 一個字符串,表示連接關(guān)閉的原因。
3)Websocket對象屬性
- readyState:只讀屬性,表示W(wǎng)ebsocket的連接狀態(tài)。
- CONNECTING — 正在連接中,對應(yīng)的值為 0;
- OPEN — 已經(jīng)連接并且可以通訊,對應(yīng)的值為 1;
- CLOSING — 連接正在關(guān)閉,對應(yīng)的值為 2;
- CLOSED — 連接已關(guān)閉或者沒有連接成功,對應(yīng)的值為 3。
- bufferedAmount:未發(fā)送至服務(wù)器的字節(jié)數(shù),只讀屬性。已被 send() 放入正在隊列中等待傳輸,但是還沒有發(fā)出的 UTF-8 文本字節(jié)數(shù)。
- binaryType:使用二進制的數(shù)據(jù)類型連接,可以是 “
blob” 或 “arraybuffer”。 - extensions:服務(wù)器選擇的通信擴展。
- protocol:打開握手期間使用的協(xié)議(服務(wù)器選擇的子協(xié)議)。
- url: webSocket 的絕對路徑。
4)websocket請求報文
// websocket握手:客戶端發(fā)送的請求頭 GET wss://www.example.cn/webSocket HTTP/1.1 // 使用的https協(xié)議, 對應(yīng)的wss請求 Host: www.example.cn Connection: Upgrade // 帶upgrade頭的http1.1消息必須含有connection頭,表示任何接受此消息的人都在轉(zhuǎn)發(fā)此消息之前處理掉connection中指定的域(即不轉(zhuǎn)發(fā)upgrade域) Upgrade: websocket // 定義轉(zhuǎn)換協(xié)議的header域,如果服務(wù)器支持,客戶端希望使用已經(jīng)建立好的http(tcp)連接 Sec-WebSocket-Version: 13 // 客戶端支持的WebSocket協(xié)議的版本列表 Origin: http://example.cn // Origin為安全使用,防止跨站攻擊,瀏覽器一般會使用這個來標識原始域,類似于Referer。但與Referer 不同的是,Origin 只包含了協(xié)議和主機名稱 Sec-WebSocket-Key: afmbhhBRQuwCLmnWDRWHxw== // 客戶端隨機生成的字符串,服務(wù)器會使用此字段組裝成另一個key值(構(gòu)造出一個SHA-1 的信息摘要)放在握手返回信息里,用于客戶端到服務(wù)器websocket的初始握手,避免夸協(xié)議攻擊 Sec-WebSocket-Protocol: chat, superchat // 首標,告訴客戶端應(yīng)用程序可使用的協(xié)議 Sec-WebSocket-Extensions: permessage-deflate // 首標,permessage-deflate:協(xié)商使用傳輸數(shù)據(jù)壓縮,client_max_window_bits:擦采用LZ77壓縮算法時,滑動窗口相關(guān)SIZE大小 // websocket握手:服務(wù)器發(fā)出的響應(yīng)頭 HTTP/1.1 101 // 服務(wù)端響應(yīng)101狀態(tài)碼、Upgrade和Sec-WebSocket-Accept首標才算連接成功,否則不能連接成功。 Server: nginx/1.12.2 Date: Sat, 11 Aug 2018 13:21:27 GMT Connection: upgrade // 指定一項或多項協(xié)議名,按優(yōu)先級排序,以逗號分隔,這里表示升級為 WebSocket 協(xié)議 Upgrade: websocket Sec-WebSocket-Accept: sLMyWetYOwus23qJyUD/fa1hztc= // 根據(jù)Sec-WebSocket-Key加上特殊字符串,計算SHA-1摘要,再進行 Base64編碼協(xié)議生成(可盡量避免普通HTTP請求被誤認為WebSocket協(xié)議) Sec-WebSocket-Protocol: chat Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15


5)websocket連接生命周期

6)簡單應(yīng)用示例
<template>
<div>
<input type="text" :value="inputVal" />
<button @click="handleSend">send</button>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const inputVal = ref("");
const handleSend = () => {
socket.send(inputVal.value);
};
// 創(chuàng)建WebSocket對象,并指定服務(wù)器的地址
const socket = new WebSocket("ws://82.157.123.54:9010/ajaxchattest");
// 與服務(wù)器建立連接:發(fā)送消息到服務(wù)器
socket.onopen = () => {
console.log("connect: ");
};
// 收到服務(wù)器發(fā)送的消息:event處理服務(wù)器返回的數(shù)據(jù)
socket.onmessage = (event) => {
console.log("receive: ", event.data);
};
// 連接或通信過程中發(fā)生錯誤
socket.onerror = (event) => {
console.log("errror: ", event.error);
};
// 與服務(wù)器斷開連接
socket.onclose = (event) => {
console.log("close: ", event.code);
};
</script>
六、websocket心跳機制
1、作用:使 WebSocket 連接保持長連接,避免斷開連接的情況發(fā)生。同時,心跳機制也可以檢查WebSocket連接的狀態(tài),及時處理異常情況。還可以減少WebSocket連接及服務(wù)器資源的消耗。
2、原理:是利用心跳包及時發(fā)送和接收數(shù)據(jù),保證WebSocket長連接不被斷開。
3、詳細流程:
- 客戶端建立WebSocket連接。
- 客戶端向服務(wù)器發(fā)送心跳數(shù)據(jù)包(心跳包是指在一定時間間隔內(nèi),WebSocket發(fā)送的空數(shù)據(jù)包),服務(wù)器接收并返回一個表示接收到心跳數(shù)據(jù)包的響應(yīng)。
- 當服務(wù)器沒有及時接收到客戶端發(fā)送的心跳數(shù)據(jù)包時,服務(wù)器會發(fā)送一個關(guān)閉連接的請求。
- 服務(wù)器定時向客戶端發(fā)送心跳數(shù)據(jù)包,客戶端接收并返回一個表示接收到心跳數(shù)據(jù)包的響應(yīng)。
- 當客戶端沒有及時接收到服務(wù)器發(fā)送的心跳數(shù)據(jù)包時,客戶端會重新連接WebSocket
4、實現(xiàn)方式
- 使用setInterval定時發(fā)送心跳包。對服務(wù)器造成很大的壓力,因為即使WebSocket連接正常,也要定時發(fā)送心跳包,從而消耗服務(wù)器資源。
- 在前端監(jiān)聽到WebSocket的onclose()事件時,重新創(chuàng)建WebSocket連接。減輕了服務(wù)器的負擔,但是在重連時可能會丟失一些數(shù)據(jù)。
5、WebSocket重連
重連意思就是在WebSocket斷開之后重新建立連接,這里指由于異常斷開需要重新連接。
常用實現(xiàn)方法有下:
- 1)前端監(jiān)聽WebSocket的onclose()事件,重新創(chuàng)建WebSocket連接。
- 2)使用WebSocket插件或庫,例如Sockjs、Stompjs等。
- 3)使用心跳機制檢測WebSocket連接狀態(tài),自動重連。
- 4)使用斷線重連插件或庫,例如ReconnectingWebSocket等。
6、通過WebSocket心跳機制,實現(xiàn)重連
思路: 在建立長連接的時候開啟心跳 > 通過和服務(wù)端發(fā)送信息,得到服務(wù)端給返回的信息,然后重置心跳 > 清除時間,再重新開啟心跳。(如果網(wǎng)絡(luò)斷開的話,會執(zhí)行方法,重新連接)
<template>
<div>
<input type="text" :value="inputVal" />
<button @click="handleSend">send</button>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const inputVal = ref("");
let ws: any = null; // websocket實例
let isConnect: Boolean = false; // 連接標識 避免重復連接
let reciveCode: any = null; // 斷線重連后,延遲5秒重新創(chuàng)建WebSocket連接,reciveCode用來存儲延遲請求的代碼
let timeoutObj: any = null; // 延時發(fā)送消息對象(啟動心跳時新建這個對象,收到消息后重置這個對象)
// websocket重連
const reConnect = () => {
// 如果已經(jīng)連上就不在重連了
if (isConnect) {
return;
}
clearTimeout(reciveCode);
// 延遲5秒重連 避免過多次過頻繁請求重連
reciveCode = setTimeout(() => {
newWebSocket();
}, 5000);
};
// 創(chuàng)建并初始化websocket實例
const newWebSocket = () => {
// 判斷當前環(huán)境是否支持Websocket
if (window.WebSocket) {
if (!ws) {
// 創(chuàng)建WebSocket對象,并指定服務(wù)器的地址
ws = new WebSocket("ws://82.157.123.54:9010/ajaxchattest");
}
// 與服務(wù)器建立連接
ws.onopen = () => {
console.log("connect: ");
isConnect = true;
// 5分鐘發(fā)一次心跳,比server端設(shè)置的連接時間稍微小一點,在接近斷開的情況下以通信的方式去重置連接時間。
timeoutObj = setTimeout(() => {
if (isConnect) ws.send(inputVal.value);
}, 300000);
};
// 收到服務(wù)器發(fā)送的消息
ws.onmessage = (event: any) => {
console.log("receive: ", event, event.data);
clearTimeout(timeoutObj);
};
// 連接或通信過程中發(fā)生錯誤
ws.onerror = (event: any) => {
console.log("errror: ", event.error);
isConnect = false; //連接錯誤 需要重連
reConnect();
};
// 與服務(wù)器斷開連接
ws.onclose = (event: any) => {
console.log("close: ", event.code);
isConnect = false;
// 連接錯誤 需要重連
reConnect();
};
} else {
console.log("當前瀏覽器不支持websocket");
}
};
const handleSend = () => {
newWebSocket();
if (ws.readyState === ws.OPEN) {
// ws開啟狀態(tài)
ws.send(inputVal.value);
} else if (ws.readyState === ws.CONNECTING) {
// 正在開啟狀態(tài),則等待1s后重新調(diào)用
setTimeout(function () {
handleSend();
}, 1000);
} else {
// 若未開啟 ,則等待1s后重新調(diào)用
setTimeout(function () {
handleSend();
}, 1000);
}
};
</script>
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vscode 左側(cè)擴展活動欄內(nèi)容消失的問題及解決方法
vscode左側(cè)活動欄默認會有 一些內(nèi)容,今天一不小心,不知道怎么的,將部分內(nèi)容搞沒了,vscode 左側(cè)擴展活動欄內(nèi)容消失了怎么辦,下面給大家分享本文幫助大家快速解決,感興趣的朋友一起看看吧2021-08-08

