Skip to content

這是一個供庫作者和高級用例使用的低級 API。

啟動服務器(Bun.listen()

要使用 Bun.listen 啟動 TCP 服務器:

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {}, // 從客戶端接收的消息
    open(socket) {}, // 套接字打開
    close(socket, error) {}, // 套接字關閉
    drain(socket) {}, // 套接字准備好接收更多數據
    error(socket, error) {}, // 錯誤處理程序
  },
});

為速度設計的 API

在 Bun 中,一組處理程序每個服務器聲明一次,而不是像 Node.js EventEmitters 或 Web 標准 WebSocket API 那樣為每個套接字分配回調。

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    open(socket) {},
    data(socket, data) {},
    drain(socket) {},
    close(socket, error) {},
    error(socket, error) {},
  },
});

對於性能敏感的服務器,為每個套接字分配監聽器會導致顯著的垃圾回收器壓力並增加內存使用。相比之下,Bun 只為每個事件分配一個處理程序函數並在所有套接字之間共享。這是一個小的優化,但會累積。

上下文數據可以在 open 處理程序中附加到套接字。

ts
type SocketData = { sessionId: string };

Bun.listen<SocketData>({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {
      socket.write(`${socket.data.sessionId}: ack`); 
    },
    open(socket) {
      socket.data = { sessionId: "abcd" }; 
    },
  },
});

要啟用 TLS,傳遞包含 keycert 字段的 tls 對象。

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {},
  },
  tls: {
    // 可以是字符串、BunFile、TypedArray、Buffer 或它們的數組
    key: Bun.file("./key.pem"), 
    cert: Bun.file("./cert.pem"), 
  },
});

keycert 字段期望你的 TLS 密鑰和證書的_內容_。這可以是字符串、BunFileTypedArrayBuffer

ts
Bun.listen({
  // ...
  tls: {
    key: Bun.file("./key.pem"), // BunFile
    key: fs.readFileSync("./key.pem"), // Buffer
    key: fs.readFileSync("./key.pem", "utf8"), // 字符串
    key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")], // 上述數組
  },
});

Bun.listen 的結果是符合 TCPSocket 接口的服務器。

ts
const server = Bun.listen({
  /* 配置 */
});

// 停止監聽
// 參數決定是否關閉活動連接
server.stop(true);

// 即使服務器仍在監聽也允許 Bun 進程退出
server.unref();

創建連接(Bun.connect()

使用 Bun.connect 連接到 TCP 服務器。使用 hostnameport 指定要連接的服務器。TCP 客戶端可以定義與 Bun.listen 相同的一組處理程序,外加幾個客戶端特定的處理程序。

ts
// 客戶端
const socket = await Bun.connect({
  hostname: "localhost",
  port: 8080,

  socket: {
    data(socket, data) {},
    open(socket) {},
    close(socket, error) {},
    drain(socket) {},
    error(socket, error) {},

    // 客戶端特定的處理程序
    connectError(socket, error) {}, // 連接失敗
    end(socket) {}, // 服務器關閉連接
    timeout(socket) {}, // 連接超時
  },
});

要要求 TLS,指定 tls: true

ts
// 客戶端
const socket = await Bun.connect({
  // ... 配置
  tls: true, 
});

熱重新加載

TCP 服務器和套接字都可以使用新的處理程序進行熱重新加載。

ts
const server = Bun.listen({
  /* 配置 */
});

// 為所有活動服務器端套接字重新加載處理程序
server.reload({
  socket: {
    data() {
      // 新的 'data' 處理程序
    },
  },
});
ts
const socket = await Bun.connect({
  /* 配置 */
});

socket.reload({
  data() {
    // 新的 'data' 處理程序
  },
});

緩沖

目前,Bun 中的 TCP 套接字不緩沖數據。對於性能敏感的代碼,仔細考慮緩沖很重要。例如,這個:

ts
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");

...性能明顯低於這個:

ts
socket.write("hello");

為了暫時簡化這個問題,考慮使用 Bun 的 ArrayBufferSink{stream: true} 選項:

ts
import { ArrayBufferSink } from "bun";

const sink = new ArrayBufferSink();
sink.start({
  stream: true, 
  highWaterMark: 1024,
});

sink.write("h");
sink.write("e");
sink.write("l");
sink.write("l");
sink.write("o");

queueMicrotask(() => {
  const data = sink.flush();
  const wrote = socket.write(data);
  if (wrote < data.byteLength) {
    // 如果套接字已滿,將其放回 sink
    sink.write(data.subarray(wrote));
  }
});

NOTE

**Corking**

支持 corking 正在計劃中,但與此同時,必須使用 drain 處理程序手動管理背壓。

Bun學習網由www.bunjs.com.cn整理維護