WebSocket
協議可以實現前後端全雙工通訊,從而取代浪費資源的長輪詢。在此協議的基礎上,可以實現前後端資料、多端資料,真正的實時響應。在學習WebSocket
的過程中,實現了一個簡化版群聊,過程和程式碼詳細記錄在這篇文章中。
本篇文章來自董沅鑫的個人網站,引用、轉載請指明出處。
檢視更多知識,或者技術交流:請訪問godbmw.com
1 概述
1.1 WebSocket 是什麼?
- 建立在 TCP 協議之上的網路通訊協議
- 全雙工通訊協議
- 沒有同源限制
- 可以傳送文字、二進位制資料等
1.2 為什麼需要 WebSocket?
瞭解計算機網路協議的人,應該都知道:HTTP 協議是一種無狀態的、無連線的、單向的應用層協議。它採用了請求/響應模型。通訊請求只能由客戶端發起,服務端對請求做出應答處理。
這種通訊模型有一個弊端:HTTP 協議無法實現伺服器主動向客戶端發起訊息。
因此,如果在客戶端想實時監聽伺服器變化,必須使用 ajax 來進行輪詢,效率低,浪費資源。
而 websocket 就可以使得前後端進行全雙工通訊(兩方都可以向對方進行資料推送),是真正的平等對話。
2 WebSocket 客戶端
支援HTML5
的瀏覽器支援 WebSocket 協議:
var ws = new WebSocket(url); // 建立一個websocket物件
2.1 WebSocket 屬性
屬性 | 描述 |
---|---|
ws.readyState | 只讀屬性 readyState 表示連線狀態,可以是以下值:0 – 表示連線尚未建立。1 – 表示連線已建立,可以進行通訊。2 – 表示連線正在進行關閉。3 – 表示連線已經關閉或者連線不能開啟。 |
ws.bufferedAmount | 只讀屬性 bufferedAmount 已被 send() 放入正在佇列中等待傳輸,但是還沒有發出的 UTF-8 文字位元組數。 |
2.2 WebSocket 方法
屬性 | 描述 |
---|---|
ws.send() | 資料傳送 |
ws.close() | 關閉連線 |
2.3 Websocket 事件
屬性 | 描述 |
---|---|
open | 連線建立觸發 |
message | 通訊時觸發 |
error | 出錯觸發 |
close | 關閉連線觸發 |
2.4 程式碼實現
假設我們在本地8080
埠開啟了websocket服務,那麼,下面程式碼可以在瀏覽器中實現和這個服務的通訊:
<body>
<script>
var ws = new WebSocket("ws://localhost:8080/");
// 建立連線觸發
ws.onopen = function () {
ws.send("open ws");
console.log("open ws");
};
// 接收服務端資料觸發
ws.onmessage = function (evt) {
var data = evt.data;
console.log("Data is ", data);
};
// 斷開連線觸發
ws.onclose = function () {
console.log("close ws");
};
</script>
</body>
3 WebSocket 服務端
關於服務端實現,根據技術選型不同,可以選用不同的庫和包。我這裡使用的是
node
的ws
庫來websocket服務端。
在阮一峰的博文提到的socket.io
庫,在瀏覽器端的寫法不相容原生API,準確來說,它們自己實現了一套websocket。所以,使用的時候前後端都應該引用第三方庫。這樣就造成了程式碼遷移性,嚴重下降。
綜上所述,ws
庫有以下優點:
- 相容性好,相容瀏覽器原生API
- 長期維護,效果穩定
- 使用方便(往下看就知道了)
4 實現群聊
4.1 群聊 服務端實現
首先,在命令列中,安裝ws
庫: npm install ws --save
現在,利用ws
來實現一個監聽8080
埠的websocket伺服器,講解都在程式碼註釋裡,一目瞭然:
const PORT = 8080; // 監聽埠
const WebSocket = require("ws"); // 引入 ws 庫
const wss = new WebSocket.Server({ port: PORT }); // 宣告wss物件
/**
* 向除了本身之外所有客戶端傳送訊息,實現群聊功能
* @param {*} data 要傳送的資料
* @param {*} ws 客戶端連線物件
*/
wss.broadcastToElse = function broadcast(data, ws) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
};
/* 客戶端接入,觸發 connection */
wss.on("connection", function connection(ws, req) {
let ip = req.connection.remoteAddress; // 通過req物件可以獲得客戶端資訊,比如:ip,headers等
/* 客戶端傳送訊息,觸發 message */
ws.on("message", function incoming(message) {
ws.send(message); // 向客戶端傳送訊息
wss.broadcastToElse(message, ws); // 向 其他的 客戶端傳送訊息,實現群聊效果
});
});
4.2 群聊 客戶端實現
為了方便編寫,這裡引入了jquery
和bootstrap
這兩個庫,只需要關注js程式碼即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>群聊</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.3.0/jquery.min.js"></script>
</head>
<body>
<div class="container">
<textarea class="form-control" rows="30" disabled="disabled" id="show-area"></textarea>
<input type="text" class="form-control" placeholder="請輸入聊天內容" id="chat-input">
<button type="button" class="btn btn-info" id="send-btn">傳送</button>
</div>
<script>
var userName = parseInt(Math.random() * 1000, 10) // 隨機使用者名稱, 以標識身份
var sendBtn = $("#send-btn"), // 傳送資訊按鈕
chatInput = $("#chat-input"), // 聊天資訊輸入框
showArea = $("#show-area") // 聊天資訊展示框
var ws = new WebSocket("ws://localhost:8080/") // 初始化WebSocket物件
sendBtn.on("click", function () {
var content = chatInput.val()
if (content.length === 0) {
return alert("請不要輸入空白內容")
}
content = "At " + (new Date()).toString() + "
" + "來自使用者" + userName + "
" + content // 拼接使用者資訊、時間資訊和訊息
ws.send(content) // 傳送訊息
chatInput.val("") // 清空輸入框
})
ws.onopen = function () { console.log("Conncet open") }
ws.onmessage = function (evt) {
var data = evt.data
showArea.val(showArea.val() + data + "
") // 重新整理聊天資訊展示框:顯示群聊資訊
}
ws.onclose = function () { console.log("Connect close") }
</script>
</body>
</html>
4.3 群聊 效果展示
首先啟動我們的服務端程式碼:node server.js
。其中,server.js
是放置服務端程式碼的檔案。
然後,我們開啟2次編寫的html
程式碼,這相當於,開啟2個客戶端。來檢測群聊功能。
5. 相關資料
- 概念解釋:
- http://www.ruanyifeng.com/blog/2017/05/websocket.html
- https://www.cnblogs.com/jingmoxukong/p/7755643.html
ws
文件:https://www.npmjs.com/package/ws
本篇文章來自董沅鑫的個人網站,引用、轉載請指明出處。
檢視更多知識,或者技術交流:請訪問godbmw