これはライブラリ開発者と高度なユースケース向けの低レベル API です。
サーバーの起動(Bun.listen())
Bun.listen で TCP サーバーを起動するには:
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 のように各ソケットにコールバックを割り当てるのではなく、サーバーごとに 1 組のハンドラーが宣言されます。
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
open(socket) {},
data(socket, data) {},
drain(socket) {},
close(socket, error) {},
error(socket, error) {},
},
});パフォーマンスに敏感なサーバーでは、各ソケットにリスナーを割り当てると、ガベージコレクターのプレッシャーが大幅に増加し、メモリ使用量が増加する可能性があります。これとは対照的に、Bun は各イベントに対して 1 つのハンドラー関数のみを割り当て、それをすべてのソケットで共有します。これは小さな最適化ですが、積み重なっていきます。
コンテキストデータは open ハンドラーでソケットに添付できます。
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 を有効にするには、key と cert フィールドを含む tls オブジェクトを渡します。
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {},
},
tls: {
// 文字列、BunFile、TypedArray、Buffer、またはそれらの配列にできます
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
},
});key フィールドと cert フィールドは、TLS 鍵と証明書の コンテンツ を期待しています。これは文字列、BunFile、TypedArray、または Buffer にできます。
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 インターフェースに準拠したサーバーです。
const server = Bun.listen({
/* config*/
});
// リッスンを停止
// パラメーターはアクティブな接続を閉じるかどうかを決定します
server.stop(true);
// サーバーがまだリッスンしていても Bun プロセスを終了させる
server.unref();接続の作成(Bun.connect())
Bun.connect を使用して TCP サーバーに接続します。接続するサーバーを hostname と port で指定します。TCP クライアントは Bun.listen と同じセットのハンドラーを定義でき、さらにいくつかのクライアント固有のハンドラーも定義できます。
// クライアント
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 を指定します。
// クライアント
const socket = await Bun.connect({
// ... config
tls: true,
});ホットリローディング
TCP サーバーとソケットの両方を新しいハンドラーでホットリロードできます。
const server = Bun.listen({
/* config */
});
// すべてのアクティブなサーバーサイドソケットのハンドラーをリロード
server.reload({
socket: {
data() {
// 新しい 'data' ハンドラー
},
},
});const socket = await Bun.connect({
/* config */
});
socket.reload({
data() {
// 新しい 'data' ハンドラー
},
});バッファリング
現在、Bun の TCP ソケットはデータをバッファリングしません。パフォーマンスに敏感なコードでは、バッファリングを慎重に考慮することが重要です。例えば、これ:
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");...はこれよりも著しくパフォーマンスが劣ります:
socket.write("hello");これを簡単にするために、{stream: true} オプションで Bun の ArrayBufferSink の使用を検討してください。
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.write(data.subarray(wrote));
}
});NOTE
**コルキング**コルキングのサポートは計画されていますが、それまでは drain ハンドラーでバックプレッシャーを手動で管理する必要があります。