首頁 >web前端 >js教程 >使用 JavaScript 和 Bun 進行 WebSocket 廣播

使用 JavaScript 和 Bun 進行 WebSocket 廣播

Susan Sarandon
Susan Sarandon原創
2024-12-09 01:29:11218瀏覽

WebSocket broadcasting with JavaScript and Bun

廣播是 WebSocket 最強大的功能之一,它允許伺服器同時向多個連接的客戶端發送訊息。與在單一客戶端和伺服器之間交換訊息的點對點通訊不同,廣播使單一訊息能夠到達一組客戶端。這使得它對於即時、協作和互動式應用程式不可或缺。


為什麼廣播很重要

廣播對於多個使用者需要保持同步或即時了解相同更新的場景至關重要。例如:

  • 群組聊天應用程式:向聊天室中的所有參與者發送訊息。
  • 協作工具:向所有使用者更新共享文件或內容變更的資訊。
  • 即時通知:向多個訂閱者廣播突發新聞、股票更新或體育比分。
  • 線上遊戲:同步多個玩家的遊戲狀態或動作。

在這種情況下,廣播可確保所有連接的使用者保持同步,而無需為每個客戶端進行單獨的伺服器調用,否則效率低且容易出現延遲。


兩種廣播方式

實施廣播時,有兩種常見策略需要考慮:

  • 向所有客戶端(包括發送者)廣播
  • 向所有發送者以外的客戶端廣播

向所有客戶端(包括發送者)廣播

此方法將訊息傳送到連接到特定通道的所有客戶端,包括發起訊息的客戶端。

此方法適用於每個客戶端(包括發送者)都需要接收廣播的情況,例如在群組聊天中顯示訊息的確認或更新。

向除發送者之外的所有用戶端廣播

在這種情況下,訊息將廣播給除發送者之外的所有用戶端。

這種方法非常適合發送者不需要在廣播中看到自己的訊息的場景,例如多人遊戲,其中的操作需要與其他玩家共享,但不需要回顯給執行該操作的玩家.

這兩種方法都有特定的用例,並且可以使用 Bun 等工具輕鬆實現,從而使開發人員能夠以最少的程式碼高效地處理廣播。


本文深入探討如何使用 Bun 設定 WebSocket 廣播,並示範了兩種廣播方法,幫助您建立強大的即時應用程式。

使用 WebSocket 進行廣播的程式碼

在本系列的第一篇文章《使用 JavaScript 和 Bun 的 WebSocket》中,我們探討了回應客戶端發送的訊息的 WebSocket 伺服器的結構。

本文將探討頻道訂閱,這是一種能夠向多個客戶端廣播訊息的機制。

我們將首先展示完整的程式碼,然後將其分解以詳細探索所有相關部分。

建立broadcast.ts檔:

console.log("? Hello via Bun! ?");
const server = Bun.serve({
  port: 8080, // defaults to $BUN_PORT, $PORT, $NODE_PORT otherwise 3000
  fetch(req, server) {
    const url = new URL(req.url);
    if (url.pathname === "/") return new Response(Bun.file("./index.html"));
    if (url.pathname === "/surprise") return new Response("?");

    if (url.pathname === "/chat") {
      if (server.upgrade(req)) {
        return; // do not return a Response
      }
      return new Response("Upgrade failed", { status: 400 });
    }

    return new Response("404!");
  },
  websocket: {
    message(ws, message) {
      console.log("✉️ A new Websocket Message is received: " + message);
      ws.send("✉️ I received a message from you:  " + message);
      ws.publish(
        "the-group-chat",
        `? Message from ${ws.remoteAddress}: ${message}`,
      );
    }, // a message is received
    open(ws) {
      console.log("? A new Websocket Connection");
      ws.subscribe("the-group-chat");
      ws.send("? Welcome baby");
      ws.publish("the-group-chat", "? A new friend is joining the Party");
    }, // a socket is opened
    close(ws, code, message) {
      console.log("⏹️ A Websocket Connection is CLOSED");
      const msg = `A Friend has left the chat`;
      ws.unsubscribe("the-group-chat");
      ws.publish("the-group-chat", msg);
    }, // a socket is closed
    drain(ws) {
      console.log("DRAIN EVENT");
    }, // the socket is ready to receive more data
  },
});
console.log(`? Server (HTTP and WebSocket) is launched ${server.url.origin}`);

setInterval(() => {
  const msg = "Hello from the Server, this is a periodic message!";
  server.publish("the-group-chat", msg);
  console.log(`Message sent to "the-group-chat": ${msg}`);
}, 5000); // 5000 ms = 5 seconds

您可以透過以下方式運行它:

bun run broadcast.ts

這段程式碼引入了廣播,允許伺服器向特定頻道中的所有訂閱客戶端發送訊息。它還區分向所有客戶端(包括發送者)廣播或排除發送者。詳細解釋如下:


初始化伺服器

const server = Bun.serve({
  port: 8080,
  ...
});

初始化與上一篇相同。
伺服器偵聽連接埠 8080,與前面的範例類似,它處理 HTTP 請求並升級 /chat 的 WebSocket 連線。


WebSocket 中的廣播

廣播允許將訊息傳送給訂閱特定頻道的所有客戶端,例如群組聊天
以下是程式碼如何實現這一點:


訂閱頻道(在開放事件中)

open(ws) {
  console.log("? A new Websocket Connection");
  ws.subscribe("the-group-chat");
  ws.send("? Welcome baby");
  ws.publish("the-group-chat", "? A new friend is joining the Party");
}
  • ws.subscribe(channel):將客戶端訂閱到頻道 the-group-chat。此頻道中的所有用戶端現在都可以接收廣播到它的訊息。
  • ws.send(...): 單獨歡迎顧客。
  • ws.publish(channel, message):向頻道中的所有客戶端廣播訊息。

廣播訊息(在訊息事件中回覆/廣播來自客戶端的訊息)

message(ws, message) {
  console.log("✉️ A new Websocket Message is received: " + message);
  ws.send("✉️ I received a message from you:  " + message);
  ws.publish("the-group-chat", `? Message from ${ws.remoteAddress}: ${message}`);
}

收到來自客戶端的訊息時:

  • 發送者透過 ws.send(...) 獲得確認。
  • 訊息使用 ws.publish(...) 廣播到「the-group-chat」中的所有用戶端(不包括寄件者)。

注意:發送者沒有收到廣播訊息,因為我們呼叫了 ws 物件的publish 方法。您應該使用伺服器物件來包含寄件者。


取消訂閱並在斷開連線時廣播(在關閉事件中)

close(ws, code, message) {
  console.log("⏹️ A Websocket Connection is CLOSED");
  const msg = `A Friend has left the chat`;
  ws.unsubscribe("the-group-chat");
  ws.publish("the-group-chat", msg);
}

當客戶端斷開連線時:

  • ws.unsubscribe(channel): 從頻道訂閱中刪除客戶端。
  • 一則訊息會廣播到頻道中所有剩餘的客戶端,通知他們斷開連線。

定期向所有客戶端發送伺服器訊息

console.log("? Hello via Bun! ?");
const server = Bun.serve({
  port: 8080, // defaults to $BUN_PORT, $PORT, $NODE_PORT otherwise 3000
  fetch(req, server) {
    const url = new URL(req.url);
    if (url.pathname === "/") return new Response(Bun.file("./index.html"));
    if (url.pathname === "/surprise") return new Response("?");

    if (url.pathname === "/chat") {
      if (server.upgrade(req)) {
        return; // do not return a Response
      }
      return new Response("Upgrade failed", { status: 400 });
    }

    return new Response("404!");
  },
  websocket: {
    message(ws, message) {
      console.log("✉️ A new Websocket Message is received: " + message);
      ws.send("✉️ I received a message from you:  " + message);
      ws.publish(
        "the-group-chat",
        `? Message from ${ws.remoteAddress}: ${message}`,
      );
    }, // a message is received
    open(ws) {
      console.log("? A new Websocket Connection");
      ws.subscribe("the-group-chat");
      ws.send("? Welcome baby");
      ws.publish("the-group-chat", "? A new friend is joining the Party");
    }, // a socket is opened
    close(ws, code, message) {
      console.log("⏹️ A Websocket Connection is CLOSED");
      const msg = `A Friend has left the chat`;
      ws.unsubscribe("the-group-chat");
      ws.publish("the-group-chat", msg);
    }, // a socket is closed
    drain(ws) {
      console.log("DRAIN EVENT");
    }, // the socket is ready to receive more data
  },
});
console.log(`? Server (HTTP and WebSocket) is launched ${server.url.origin}`);

setInterval(() => {
  const msg = "Hello from the Server, this is a periodic message!";
  server.publish("the-group-chat", msg);
  console.log(`Message sent to "the-group-chat": ${msg}`);
}, 5000); // 5000 ms = 5 seconds

每 5 秒,伺服器使用 server.publish(...) 向「the-group-chat」頻道中的所有用戶端廣播訊息。這裡我們使用伺服器對象。


關鍵方法

  • ws.subscribe(channel): 訂閱目前WebSocket客戶端到一個頻道進行群組通訊。
  • ws.publish(channel, message):向指定頻道中的所有用戶端廣播訊息(不包括發送者)。
  • server.publish(channel, message):與 ws.publish 類似,但在伺服器層級用於向所有訂閱的用戶端(包括發送者)廣播。
  • ws.unsubscribe(channel): 從頻道中刪除目前客戶端。

流程範例

  1. 客戶端連線到 /chat,訂閱「the-group-chat」。
  2. 客戶端向伺服器發送訊息:
    • 訊息將回顯給寄件者。
    • 伺服器將訊息廣播給頻道中的所有其他客戶端。
  3. 當客戶端斷開連線時:
    • 已從頻道取消訂閱。
    • 伺服器通知其餘客戶端有關斷開連線的資訊。
  4. 每 5 秒,伺服器會向所有用戶端發送定期廣播訊息。

結論

WebSockets 是建立即時、互動式 Web 應用程式的強大工具。與傳統的 HTTP 通訊不同,WebSocket 提供持久的雙向通道,支援伺服器和連線的用戶端之間的即時訊息交換。這使得它們非常適合即時聊天、協作工具、遊戲或任何低延遲通訊至關重要的應用程式。

在本文(以及本系列)中,我們探索了使用 Bun 設定 WebSocket 伺服器、處理客戶端連線以及向訂閱客戶端廣播訊息的基礎知識。我們也示範如何實作一個簡單的群組聊天系統,用戶端可以加入頻道、傳送訊息以及從其他用戶端和伺服器本身接收更新。

透過利用 Bun 內建的 WebSocket 支援和訂閱、發布和取消訂閱等功能,管理即時通訊變得非常容易。無論您是發送定期更新、向所有用戶端廣播還是管理特定通道,WebSocket 都提供了一種高效且可擴展的方式來處理此類需求。

以上是使用 JavaScript 和 Bun 進行 WebSocket 廣播的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn