> ## Documentation Index
> Fetch the complete documentation index at: https://bun.ll1025.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# TCP

> 使用 Bun 的原生 TCP API 实现性能敏感型系统，如数据库客户端、游戏服务器或任何需要通过 TCP（而非 HTTP）通信的场景

Bun 的 TCP API 是底层 API，面向库作者和高级用例。

## 启动服务器 (`Bun.listen()`)

使用 `Bun.listen` 启动 TCP 服务器：

```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {}, // 收到客户端消息
    open(socket) {}, // 套接字已打开
    close(socket, error) {}, // 套接字已关闭
    drain(socket) {}, // 套接字已准备好接收更多数据
    error(socket, error) {}, // 错误处理器
  },
});
```

<Accordion title="为速度设计的 API">
  在 Bun 中，你为每个服务器声明一组处理器，而不是像 Node.js `EventEmitters` 或 Web 标准的 `WebSocket` API 那样为每个套接字分配回调。

  ```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
  Bun.listen({
    hostname: "localhost",
    port: 8080,
    socket: {
      open(socket) {},
      data(socket, data) {},
      drain(socket) {},
      close(socket, error) {},
      error(socket, error) {},
    },
  });
  ```

  对于性能敏感的服务器，为每个套接字分配监听器可能会导致严重的垃圾回收压力并增加内存使用。相比之下，Bun 只为每个事件分配一个处理器函数，并在所有套接字之间共享。这是一个小的优化，但效果累积起来。
</Accordion>

在 `open` 处理器中向套接字附加上下文数据。

```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
type SocketData = { sessionId: string };

Bun.listen<SocketData>({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {
      socket.write(`${socket.data.sessionId}: 确认`); // [!code ++]
    },
    open(socket) {
      socket.data = { sessionId: "abcd" }; // [!code ++]
    },
  },
});
```

要启用 TLS，传递包含 `key` 和 `cert` 字段的 `tls` 对象。

```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {},
  },
  tls: {
    // 可以是 string、BunFile、TypedArray、Buffer 或其数组
    key: Bun.file("./key.pem"), // [!code ++]
    cert: Bun.file("./cert.pem"), // [!code ++]
  },
});
```

`key` 和 `cert` 字段期望的是 TLS 密钥和证书的**内容**。可以是字符串、`BunFile`、`TypedArray` 或 `Buffer`。

```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
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")], // 上述类型的数组
  },
});
```

`Bun.listen` 返回一个符合 `TCPSocketListener` 接口的服务器。

```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const server = Bun.listen({
  /* 配置 */
});

// 停止监听
// 参数决定是否关闭活动连接
server.stop(true);

// 即使服务器仍在监听，也允许 Bun 进程退出
server.unref();
```

***

## 创建连接 (`Bun.connect()`)

使用 `Bun.connect` 连接到 TCP 服务器。使用 `hostname` 和 `port` 指定服务器。TCP 客户端可以定义与 `Bun.listen` 相同的一组处理器，外加一些客户端特定的处理器。

```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
// 客户端
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 theme={null}
// 客户端
const socket = await Bun.connect({
  // ... 配置
  tls: true, // [!code ++]
});
```

***

## 热重载

TCP 服务器和套接字都可以使用新处理器进行热重载。

<CodeGroup>
  ```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
  const server = Bun.listen({
    /* 配置 */
  });

  // 重新加载所有活动服务端套接字的处理器
  server.reload({
    socket: {
      data() {
        // 新的 'data' 处理器
      },
    },
  });
  ```

  ```ts client.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
  const socket = await Bun.connect({
    /* 配置 */
  });

  socket.reload({
    data() {
      // 新的 'data' 处理器
    },
  });
  ```
</CodeGroup>

***

## 缓冲

Bun 中的 TCP 套接字不会缓冲数据，因此性能敏感的代码应自行缓冲写入。例如，这段代码：

```ts theme={null}
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");
```

...性能远不如这段代码：

```ts theme={null}
socket.write("hello");
```

要缓冲写入，请使用 Bun 的 `ArrayBufferSink` 并设置 `{stream: true}` 选项：

```ts server.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
import { ArrayBufferSink } from "bun";

const sink = new ArrayBufferSink();
sink.start({
  stream: true, // [!code ++]
  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
    sink.write(data.subarray(wrote));
  }
});
```

<Note>
  **Corking**

  计划支持 corking，但在此期间，必须使用 `drain` 处理器手动管理背压。
</Note>
