Skip to content

これはライブラリ開発者と高度なユースケース向けの低レベル API です。

サーバーの起動(Bun.listen()

Bun.listen で TCP サーバーを起動するには:

ts
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 組のハンドラーが宣言されます。

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    open(socket) {},
    data(socket, data) {},
    drain(socket) {},
    close(socket, error) {},
    error(socket, error) {},
  },
});

パフォーマンスに敏感なサーバーでは、各ソケットにリスナーを割り当てると、ガベージコレクターのプレッシャーが大幅に増加し、メモリ使用量が増加する可能性があります。これとは対照的に、Bun は各イベントに対して 1 つのハンドラー関数のみを割り当て、それをすべてのソケットで共有します。これは小さな最適化ですが、積み重なっていきます。

コンテキストデータは open ハンドラーでソケットに添付できます。

ts
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 を有効にするには、keycert フィールドを含む tls オブジェクトを渡します。

ts
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 鍵と証明書の コンテンツ を期待しています。これは文字列、BunFileTypedArray、または Buffer にできます。

ts
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 インターフェースに準拠したサーバーです。

ts
const server = Bun.listen({
  /* config*/
});

// リッスンを停止
// パラメーターはアクティブな接続を閉じるかどうかを決定します
server.stop(true);

// サーバーがまだリッスンしていても Bun プロセスを終了させる
server.unref();

接続の作成(Bun.connect()

Bun.connect を使用して TCP サーバーに接続します。接続するサーバーを hostnameport で指定します。TCP クライアントは Bun.listen と同じセットのハンドラーを定義でき、さらにいくつかのクライアント固有のハンドラーも定義できます。

ts
// クライアント
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 を指定します。

ts
// クライアント
const socket = await Bun.connect({
  // ... config
  tls: true, 
});

ホットリローディング

TCP サーバーとソケットの両方を新しいハンドラーでホットリロードできます。

ts
const server = Bun.listen({
  /* config */
});

// すべてのアクティブなサーバーサイドソケットのハンドラーをリロード
server.reload({
  socket: {
    data() {
      // 新しい 'data' ハンドラー
    },
  },
});
ts
const socket = await Bun.connect({
  /* config */
});

socket.reload({
  data() {
    // 新しい 'data' ハンドラー
  },
});

バッファリング

現在、Bun の TCP ソケットはデータをバッファリングしません。パフォーマンスに敏感なコードでは、バッファリングを慎重に考慮することが重要です。例えば、これ:

ts
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");

...はこれよりも著しくパフォーマンスが劣ります:

ts
socket.write("hello");

これを簡単にするために、{stream: true} オプションで Bun の ArrayBufferSink の使用を検討してください。

ts
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 ハンドラーでバックプレッシャーを手動で管理する必要があります。

Bun by www.bunjs.com.cn 編集