Dies ist eine Low-Level-API, die für Bibliotheksautoren und fortgeschrittene Anwendungsfälle gedacht ist.
Starten eines Servers (Bun.listen())
Um einen TCP-Server mit Bun.listen zu starten:
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {}, // vom Client empfangene Nachricht
open(socket) {}, // Socket geöffnet
close(socket, error) {}, // Socket geschlossen
drain(socket) {}, // Socket bereit für mehr Daten
error(socket, error) {}, // Fehler-Handler
},
});Eine API, die für Geschwindigkeit entwickelt wurde">
In Bun wird ein Satz von Handlern einmal pro Server deklariert, anstatt Callbacks jedem Socket zuzuweisen, wie bei Node.js EventEmitters oder der Web-Standard-WebSocket-API.
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
open(socket) {},
data(socket, data) {},
drain(socket) {},
close(socket, error) {},
error(socket, error) {},
},
});Bei leistungsempfindlichen Servern kann das Zuweisen von Listenern zu jedem Socket erheblichen Garbage-Collector-Druck verursachen und die Speichernutzung erhöhen. Im Gegensatz dazu allokiert Bun nur eine Handler-Funktion für jedes Ereignis und teilt sie unter allen Sockets. Dies ist eine kleine Optimierung, aber sie summiert sich.
Kontextuelle Daten können einem Socket im open-Handler angehängt werden.
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" };
},
},
});Um TLS zu aktivieren, übergeben Sie ein tls-Objekt, das key- und cert-Felder enthält.
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {},
},
tls: {
// kann string, BunFile, TypedArray, Buffer oder Array davon sein
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
},
});Die key- und cert-Felder erwarten die Inhalte Ihres TLS-Schlüssels und -Zertifikats. Dies kann ein String, BunFile, TypedArray oder Buffer sein.
Bun.listen({
// ...
tls: {
key: Bun.file("./key.pem"), // BunFile
key: fs.readFileSync("./key.pem"), // Buffer
key: fs.readFileSync("./key.pem", "utf8"), // string
key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")], // Array davon
},
});Das Ergebnis von Bun.listen ist ein Server, der der TCPSocket-Schnittstelle entspricht.
const server = Bun.listen({
/* config*/
});
// Aufhören zu lauschen
// Parameter bestimmt, ob aktive Verbindungen geschlossen werden
server.stop(true);
// Bun-Prozess beenden lassen, auch wenn Server noch lauscht
server.unref();Eine Verbindung herstellen (Bun.connect())
Verwenden Sie Bun.connect, um eine Verbindung zu einem TCP-Server herzustellen. Geben Sie den Server, mit dem verbunden werden soll, mit hostname und port an. TCP-Clients können denselben Satz von Handlern wie Bun.listen definieren, plus ein paar Client-spezifische Handler.
// Der Client
const socket = await Bun.connect({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {},
open(socket) {},
close(socket, error) {},
drain(socket) {},
error(socket, error) {},
// Client-spezifische Handler
connectError(socket, error) {}, // Verbindung fehlgeschlagen
end(socket) {}, // Verbindung vom Server geschlossen
timeout(socket) {}, // Verbindung abgelaufen
},
});Um TLS zu erfordern, geben Sie tls: true an.
// Der Client
const socket = await Bun.connect({
// ... config
tls: true,
});Hot Reloading
Sowohl TCP-Server als auch Sockets können mit neuen Handlern hot-reloaded werden.
const server = Bun.listen({
/* config */
});
// reloadt Handler für alle aktiven Server-seitigen Sockets
server.reload({
socket: {
data() {
// neuer 'data'-Handler
},
},
});const socket = await Bun.connect({
/* config */
});
socket.reload({
data() {
// neuer 'data'-Handler
},
});Pufferung
Derzeit puffern TCP-Sockets in Bun keine Daten. Für leistungsempfindlichen Code ist es wichtig, die Pufferung sorgfältig zu berücksichtigen. Zum Beispiel dies:
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");...schneidet erheblich schlechter ab als dies:
socket.write("hello");Um dies vorerst zu vereinfachen, erwägen Sie die Verwendung von Buns ArrayBufferSink mit der {stream: true}-Option:
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) {
// zurück in den Sink legen, wenn der Socket voll ist
sink.write(data.subarray(wrote));
}
});NOTE
**Corking**Unterstützung für Corking ist geplant, aber in der Zwischenzeit muss Backpressure manuell mit dem drain-Handler verwaltet werden.