适配器

适配器是一个服务器端组件,负责将事件广播到所有或部分客户端。

当扩展到多个 Socket.IO 服务器时,您需要将默认的内存适配器替换为另一个实现,以便将事件正确路由到所有客户端。

除了内存适配器之外,还有四种官方实现:

(真棒!)社区还维护了其他几个选项:

请注意,当使用多个 Socket.IO 服务器和 HTTP 长轮询时,仍然需要启用粘性会话。更多信息在这里.

API

您可以通过以下方式访问适配器实例:

  1. // main namespace
  2. const mainAdapter = io.of("/").adapter; // WARNING! io.adapter() will not work
  3. // custom namespace
  4. const adminAdapter = io.of("/admin").adapter;

socket.io@3.1.0开始,每个 Adapter 实例都会发出以下事件:

  • create-room (argument: room)
  • delete-room (argument: room)
  • join-room (argument: room, id)
  • leave-room (argument: room, id)

例子:

  1. io.of("/").adapter.on("create-room", (room) => {
  2. console.log(`room ${room} was created`);
  3. });
  4. io.of("/").adapter.on("join-room", (room, id) => {
  5. console.log(`socket ${id} has joined room ${room}`);
  6. });

Emitter

大多数适配器实现都带有相关的发射器包,它允许从另一个 Node.js 进程与一组 Socket.IO 服务器进行通信。

Emitter diagram

例如,这在微服务设置中可能很有用,其中所有客户端都连接到微服务 M1,而微服务 M2 使用发射器来广播数据包(单向通信)。

Emitter cheatsheet

  1. // to all clients
  2. emitter.emit(/* ... */);
  3. // to all clients in "room1"
  4. emitter.to("room1").emit(/* ... */);
  5. // to all clients in "room1" except those in "room2"
  6. emitter.to("room1").except("room2").emit(/* ... */);
  7. const adminEmitter = emitter.of("/admin");
  8. // to all clients in the "admin" namespace
  9. adminEmitter.emit(/* ... */);
  10. // to all clients in the "admin" namespace and in the "room1" room
  11. adminEmitter.to("room1").emit(/* ... */);

The emitter also supports the utility methods that were added in socket.io@4.0.0:

  • socketsJoin()
  1. // make all Socket instances join the "room1" room
  2. emitter.socketsJoin("room1");
  3. // make all Socket instances of the "admin" namespace in the "room1" room join the "room2" room
  4. emitter.of("/admin").in("room1").socketsJoin("room2");
  • socketsLeave()
  1. // make all Socket instances leave the "room1" room
  2. emitter.socketsLeave("room1");
  3. // make all Socket instances in the "room1" room leave the "room2" and "room3" rooms
  4. emitter.in("room1").socketsLeave(["room2", "room3"]);
  5. // make all Socket instances in the "room1" room of the "admin" namespace leave the "room2" room
  6. emitter.of("/admin").in("room1").socketsLeave("room2");
  • disconnectSockets()
  1. // make all Socket instances disconnect
  2. emitter.disconnectSockets();
  3. // make all Socket instances in the "room1" room disconnect (and discard the low-level connection)
  4. emitter.in("room1").disconnectSockets(true);
  5. // make all Socket instances in the "room1" room of the "admin" namespace disconnect
  6. emitter.of("/admin").in("room1").disconnectSockets();
  7. // this also works with a single socket ID
  8. emitter.of("/admin").in(theSocketId).disconnectSockets();
  • serverSideEmit()
  1. // emit an event to all the Socket.IO servers of the cluster
  2. emitter.serverSideEmit("hello", "world");
  3. // Socket.IO server (server-side)
  4. io.on("hello", (arg) => {
  5. console.log(arg); // prints "world"
  6. });