簡介
ws模塊是Node端的一個WebSocket協議的實現,該協議允許客戶端(一般是瀏覽器)持久化和服務端的連接.
這種可以持續連接的特性使得WebScoket特別適合用於適合用於遊戲或者聊天室等使用場景.
ws模塊相較於其他基於WebSocket協議的模塊來說非常的純粹.
他只關注基於WebSocket協議的實現,其他例如Socket.io
提供了回退手段,當WebSocket無法使用的時候會利用輪詢來模擬持久化連接.
WebSocket協議被設計的十分簡單且有效,沒有了解過的朋友可以先了解一下,這裏附上幾個介紹WebSocket協議的文章.
https://developer.mozilla.org...
http://www.ruanyifeng.com/blo...
https://www.cnblogs.com/fuqia...
本文章主要分爲如下幾個部分:
- ws模塊介紹
- ws搭建服務器
- ws製作客戶端
- ws配合Vue製作一個簡單在線的聊天室
本文章中使用的ws版本爲6.1.0
.
ws模塊介紹
ws模塊基本分爲兩個部分,有着如下的特點:
-
server部分
- 使用ws模塊可以配置進行流式傳輸
- 基於現有的Http/s服務器進行建立連接
- 基於內部的Http模塊直接建立服務器
- 手動控制協議的升級
-
client部分
- 幾乎和瀏覽器端一致API的客戶端實現
引入ws模塊:
const WebSocket = require('ws');
創建服務器:
const wss = new WebSocket.Server({
port:8080
});
創建客戶端:
const ws = new WebSocket('ws://127.0.0.1:8080');
ws服務器建立
ws服務器的建立可以基於一個Http服務器或者使用內部的Http服務器,爲了簡單介紹後面的例子一律使用內部服務器.
ws模塊的服務端的創建和使用非常類似於Node的Http模塊:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 }); // 監聽端口
wss.on('connection', function connection(ws) { // 當服務器和客戶端握手成功後觸發該事件,而第一個參數就是一個client對象
ws.on('message', function incoming(message) {
console.log('客戶端發送的數據', message);
});
ws.send('something'); // 響應內容
});
這裏需要指明的一點是,WebSocket是通過Http進行協議升級後爲WebSocket協議的.
在connection
事件中第一個參數爲一個Client對象實際上就是ws模塊的客戶端實例.
ws模塊用這個對象來描述一個連接對象.
而第二個參數是一個http.IncomingMessage
對象,可以利用他來獲取請求參數例如Cookie
.
這裏大家只要記住connection
事件的第一個參數是一個ws
實例對象就可以了,後面會介紹這個對象.
Server端有很多事件和屬性還有方法,這裏我只寫出了一些常見的參數,詳細的官方文檔我會添加在文章的末尾.
事件:
- close 服務器關閉時候觸發
- connection 客戶端和服務器握手完成後觸發
- error 服務器底層錯誤時候觸發
- headers 客戶端請求升級協議的請求觸發.這個時候還沒有建立WebSocket通信,你可以在這個事件檢查和修改Header
- listening 服務器啓動監聽時候觸發
屬性:
- server.clients 一個Set對象保存了服務器所有的已建立的連接對象,只有在Server的構造函數中clientTracking爲True的時候纔有效.
方法:
- close() 調用後關閉內部的Http服務器,一旦數據傳輸完成後將自動關閉所有的客戶端連接
客戶端建立
上文中已經提到了ws模塊提供的客戶端API幾乎和瀏覽器一致,確實如此,但是它提供了比瀏覽器端更加豐富的功能.
例子使用客戶端(該例子來源於官網):
const WebSocket = require('ws');
const ws = new WebSocket('wss://echo.websocket.org/', {
origin: 'https://websocket.org'
});
ws.on('open', function open() { // 握手成功後觸發
console.log('connected');
ws.send(Date.now());
});
ws.on('close', function close() {
console.log('disconnected');
});
ws.on('message', function incoming(data) { // 服務器信息到達時候觸發
console.log(`Roundtrip time: ${Date.now() - data} ms`);
setTimeout(function timeout() {
ws.send(Date.now());
}, 500);
});
echo.websocket.org
這個網站中提供了一個簡單的webSocket的服務器,你可以直接在Node中運行上面這個例子.
同樣的客戶端也提供了豐富的事件屬性和方法,這裏簡單的介紹了一些最常使用的內容:
-
事件
- close 連接關閉的時候觸發.
- error 底層錯誤的時候觸發,例如服務器無應答導致的超時.
- message 服務器發送數據到達的時候觸發
- open 當服務器建立連接的時候觸發
-
方法
- addEventListener
- removeEventListener
- send 用於向服務器發送數據
- close 關閉連接(當所本次數據接收或者發送完成後)
- terminate 直接關閉連接
-
屬性
- readyState 當前連接的狀態 一共四個值 0 連接中 1 打開 3 關閉中 4 關閉 (和瀏覽器端的狀態碼完全一致)
實例
服務器和客戶端交互
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('服務器接受到客戶端傳送的內容:', message);
});
// 服務器發送的數據
ws.send('這是服務器發送的數據');
});
const ws = new WebSocket('ws://127.0.0.1:8080');
ws.on('open', function open() {
// 客戶端發送的數據
ws.send('我是客戶端');
});
ws.on('message', function incoming(data) {
// 接受到服務端發送的數據
console.log('客戶端接受到服務器的內容',data);
});
輸出:
客戶端接受到服務器的內容 這是服務器發送的數據
服務器接受到客戶端傳送的內容: 我是客戶端
廣播消息
廣播消息的基本原理就是獲取服務器在connection
事件中傳入的client對象,然後client對象都收集起來,然後迭代調用send
方法.
官方的例子:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
// 給服務器對象上掛載一個廣播的方法,向所有人廣播
wss.broadcast = function broadcast(data) {
// 獲取服務器所有的連接然後迭代
wss.clients.forEach(function each(client) {
// 如果連接是打開狀態
if (client.readyState === WebSocket.OPEN) {
// 發送消息
client.send(data);
}
});
};
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(data) {
// 迭代服務器中的所有的客戶端對象
wss.clients.forEach(function each(client) {
// 如果連接狀態是打開狀態,且不是當前客戶端對象
if (client !== ws && client.readyState === WebSocket.OPEN) {
// 發送消息
client.send(data);
}
});
});
});
瀏覽器端和服務器交互
服務器:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('服務器接受到客戶端傳送的內容:', message);
});
// 服務器發送的數據
ws.send('這是服務器發送的數據');
});
瀏覽器:
const client = new WebSocket('ws://127.0.0.1:8080');
client.addEventListener('open',()=>{
// 客戶端發送的數據
client.send('我是客戶端');
});
client.addEventListener('message',(data)=>{
// 接受到服務端發送的數據
console.log('客戶端接受到服務器的內容', data);
});
瀏覽器客戶端和ws客戶端異同
特性 | 瀏覽器 | ws客戶端 |
---|---|---|
使用on方法添加事件 | 不可以 | 可以 |
使用addEventListener | 可以 | 可以 |
使用onerror,onclose... | 可以 | 可以 |
message事件,evnt.data獲取數據 | 是 | 否 |
readyState屬性 | 是 | 是 |
使用Vue+ws來製作一個在線聊天室
代碼已放到github:
https://github.com/uioz/Simpl...
注意:沒有使用構建工具.
注意:該項目服務器部分是使用TS編寫的,但是客戶端沒有使用TS.
引用
npm指引包含:
- 二進制數據的傳輸和壓縮.
- 外部Http/s服務器升級爲WebSocket的具體使用方式.
- 一個Http對應多個WebSocketServer
- 心跳超時檢測.
- 客戶端ip獲取
https://www.npmjs.com/package/ws
API手冊:
https://github.com/websockets...