ws模組指南+Vue線上聊天室

ASCll發表於2019-02-16

簡介

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…

相關文章