UDP
使用 Bun 的 UDP API 實現具有高階即時需求的服務,例如語音聊天。
繫結一個 UDP 套接字 (Bun.udpSocket())
要建立一個新的(繫結的)UDP 套接字:
const socket = await Bun.udpSocket({});
console.log(socket.port); // 由作業系統分配
指定埠:
const socket = await Bun.udpSocket({
port: 41234, // [!code ++]
});
console.log(socket.port); // 41234
傳送資料包
指定要傳送的資料、目標埠和目標地址。
socket.send("Hello, world!", 41234, "127.0.0.1");
地址必須是有效的 IP 地址。send 不會執行 DNS
解析,因為它旨在用於低延遲操作。
接收資料包
建立套接字時,新增一個 data 回撥來處理傳入的資料包:
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 通訊(尤其是客戶端通訊)只涉及一個對等方。 在這種情況下,你可以將套接字連線到該對等方,這會為你傳送的每個資料包設定目標地址, 並將傳入的資料包限制為僅接收來自該對等方的資料包。
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 將陣列作為唯一引數。陣列中的每組三個元素描述一個數據包:
要傳送的資料、目標埠和目標地址。
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 接收一個陣列,陣列中的每個元素都是要傳送給對等方的資料。
const socket = await Bun.udpSocket({
connect: {
port: 41234,
hostname: "localhost",
},
});
socket.sendMany(["foo", "bar", "baz"]);
sendMany 傳回成功傳送的資料包數量。與 send 一樣,它只接受有效的 IP 地址
作為目標地址,並且不會執行 DNS 解析。
處理背壓
你傳送的資料包可能無法放入作業系統的資料包緩衝區。當出現以下情況時,你可以檢測到這一點:
send傳回falsesendMany傳回的數字小於你指定的資料包數量
在這兩種情況下,套接字再次變為可寫時,Bun 都會呼叫 drain 套接字處理程序:
const socket = await Bun.udpSocket({
socket: {
drain(socket) {
// 繼續傳送資料
},
},
});
套接字選項
UDP 套接字支援設定各種套接字選項:
const socket = await Bun.udpSocket({});
// 啟用廣播,傳送資料包到廣播地址
socket.setBroadcast(true);
// 設定出站資料包的 IP TTL(生存時間)
socket.setTTL(64);
多播
Bun 支援 UDP 套接字的多播操作。使用 addMembership 和 dropMembership 加入和離開多播組:
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");
其他多播選項:
// 設定多播包的 TTL(網路跳數)
socket.setMulticastTTL(2);
// 控制多播包是否迴環到本地套接字
socket.setMulticastLoopback(true);
// 指定用於出站多播包的介面
socket.setMulticastInterface("192.168.1.100");
對於源特定多播(SSM),使用 addSourceSpecificMembership 和 dropSourceSpecificMembership:
socket.addSourceSpecificMembership("10.0.0.1", "232.0.0.1");
socket.dropSourceSpecificMembership("10.0.0.1", "232.0.0.1");