執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

UDP

使用 Bun 的 UDP API 實現具有高階即時需求的服務,例如語音聊天。

繫結一個 UDP 套接字 (Bun.udpSocket())

要建立一個新的(繫結的)UDP 套接字:

TypeScript
const socket = await Bun.udpSocket({});
console.log(socket.port); // 由作業系統分配

指定埠:

TypeScript
const socket = await Bun.udpSocket({
  port: 41234, // [!code ++]
});

console.log(socket.port); // 41234

傳送資料包

指定要傳送的資料、目標埠和目標地址。

TypeScript
socket.send("Hello, world!", 41234, "127.0.0.1");

地址必須是有效的 IP 地址。send 不會執行 DNS 解析,因為它旨在用於低延遲操作。

接收資料包

建立套接字時,新增一個 data 回撥來處理傳入的資料包:

server.ts
const server = await Bun.udpSocket({
  socket: {
    data(socket, buf, port, addr) {
      console.log(`來自 ${addr}:${port} 的訊息:`);
      console.log(buf.toString());
    },
  },
});

const client = await Bun.udpSocket({});
client.send("Hello!", server.port, "127.0.0.1");

連線

UDP 沒有連線的概念,但許多 UDP 通訊(尤其是客戶端通訊)只涉及一個對等方。 在這種情況下,你可以將套接字連線到該對等方,這會為你傳送的每個資料包設定目標地址, 並將傳入的資料包限制為僅接收來自該對等方的資料包。

server.ts
const server = await Bun.udpSocket({
  socket: {
    data(socket, buf, port, addr) {
      console.log(`來自 ${addr}:${port} 的訊息:`);
      console.log(buf.toString());
    },
  },
});

const client = await Bun.udpSocket({
  connect: {
    port: server.port,
    hostname: "127.0.0.1",
  },
});

client.send("Hello");

連線在作業系統層面實現,因此也可以提升效能。

使用 sendMany() 一次傳送多個數據包

要在不為每個資料包執行一次系統呼叫的情況下發送大量資料包,可以使用 sendMany() 對它們進行批處理。

對於未連線的套接字,sendMany 將陣列作為唯一引數。陣列中的每組三個元素描述一個數據包: 要傳送的資料、目標埠和目標地址。

server.ts
const socket = await Bun.udpSocket({});

// 一次操作中傳送 'Hello' 到 127.0.0.1:41234,以及 'foo' 到 1.1.1.1:53
socket.sendMany(["Hello", 41234, "127.0.0.1", "foo", 53, "1.1.1.1"]);

對於已連線的套接字,sendMany 接收一個陣列,陣列中的每個元素都是要傳送給對等方的資料。

server.ts
const socket = await Bun.udpSocket({
  connect: {
    port: 41234,
    hostname: "localhost",
  },
});

socket.sendMany(["foo", "bar", "baz"]);

sendMany 傳回成功傳送的資料包數量。與 send 一樣,它只接受有效的 IP 地址 作為目標地址,並且不會執行 DNS 解析。

處理背壓

你傳送的資料包可能無法放入作業系統的資料包緩衝區。當出現以下情況時,你可以檢測到這一點:

  • send 傳回 false
  • sendMany 傳回的數字小於你指定的資料包數量

在這兩種情況下,套接字再次變為可寫時,Bun 都會呼叫 drain 套接字處理程序:

TypeScript
const socket = await Bun.udpSocket({
  socket: {
    drain(socket) {
      // 繼續傳送資料
    },
  },
});

套接字選項

UDP 套接字支援設定各種套接字選項:

TypeScript
const socket = await Bun.udpSocket({});

// 啟用廣播,傳送資料包到廣播地址
socket.setBroadcast(true);

// 設定出站資料包的 IP TTL(生存時間)
socket.setTTL(64);

多播

Bun 支援 UDP 套接字的多播操作。使用 addMembership 和 dropMembership 加入和離開多播組:

TypeScript
const socket = await Bun.udpSocket({});

// 加入多播組
socket.addMembership("224.0.0.1");

// 指定介面加入多播組
socket.addMembership("224.0.0.1", "192.168.1.100");

// 離開多播組
socket.dropMembership("224.0.0.1");

其他多播選項:

TypeScript
// 設定多播包的 TTL(網路跳數)
socket.setMulticastTTL(2);

// 控制多播包是否迴環到本地套接字
socket.setMulticastLoopback(true);

// 指定用於出站多播包的介面
socket.setMulticastInterface("192.168.1.100");

對於源特定多播(SSM),使用 addSourceSpecificMembership 和 dropSourceSpecificMembership:

TypeScript
socket.addSourceSpecificMembership("10.0.0.1", "232.0.0.1");
socket.dropSourceSpecificMembership("10.0.0.1", "232.0.0.1");