使用 Bun 的 UDP API 來實作具有進階即時需求的服務,例如語音聊天。
綁定 UDP socket (Bun.udpSocket()
)
建立新的(已綁定)UDP socket
const socket = await Bun.udpSocket({})
console.log(socket.port); // assigned by the operating system
指定埠號
const socket = await Bun.udpSocket({
port: 41234
})
console.log(socket.port); // 41234
發送資料包
指定要發送的資料,以及目標埠號和位址。
socket.send("Hello, world!", 41234, "127.0.0.1");
請注意,位址必須是有效的 IP 位址 - send
不執行 DNS 解析,因為其目的是用於低延遲操作。
接收資料包
建立 socket 時,新增一個回呼函式來指定收到封包時應執行的動作
const server = await Bun.udpSocket({
socket: {
data(socket, buf, port, addr) {
console.log(`message from ${addr}:${port}:`)
console.log(buf.toString());
}
}
})
const client = await Bun.udpSocket({});
client.send("Hello!", server.port, "127.0.0.1");
連線
雖然 UDP 沒有連線的概念,但許多 UDP 通訊(尤其作為客戶端)僅涉及單一對等節點。 在這種情況下,將 socket 連線到該對等節點可能很有益,這會指定所有封包要發送到哪個位址 並將傳入的封包限制為僅來自該對等節點。
const server = await Bun.udpSocket({
socket: {
data(socket, buf, port, addr) {
console.log(`message from ${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()
API 使這成為可能
對於未連線的 socket,sendMany
接受一個陣列作為其唯一引數。每組三個陣列元素描述一個封包 第一個項目是要發送的資料,第二個是目標埠號,最後一個是目標位址。
const socket = await Bun.udpSocket({})
// sends 'Hello' to 127.0.0.1:41234, and 'foo' to 1.1.1.1:53 in a single operation
socket.sendMany(['Hello', 41234, '127.0.0.1', 'foo', 53, '1.1.1.1'])
對於已連線的 socket,sendMany
僅接受一個陣列,其中每個元素代表要發送到對等節點的資料。
const socket = await Bun.udpSocket({
connect: {
port: 41234,
hostname: 'localhost',
}
});
socket.sendMany(['foo', 'bar', 'baz']);
sendMany
傳回成功發送的封包數量。與 send
相同,sendMany
僅接受有效的 IP 位址 作為目的地,因為它不執行 DNS 解析。
處理背壓
可能會發生您要發送的封包不適合作業系統的封包緩衝區的情況。您可以偵測到這種情況 發生在當
send
傳回false
sendMany
傳回的數字小於您指定的封包數量 在這種情況下,一旦 socket 再次可寫入,就會呼叫drain
socket 處理常式。
const socket = await Bun.udpSocket({
socket: {
drain(socket) {
// continue sending data
}
}
});