首页 >web前端 >js教程 >使用 JavaScript 和 Bun 进行 WebSocket 广播

使用 JavaScript 和 Bun 进行 WebSocket 广播

Susan Sarandon
Susan Sarandon原创
2024-12-09 01:29:11226浏览

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