Spec-Zone.ru › Socket.IO 3

Комнаты

Комната — это произвольный канал, к которому могут join и leave сокеты. Он может использоваться для трансляции событий подмножеству клиентов:

Room diagram

Обратите внимание, что комнаты — это понятие только сервера (т. е. клиент не имеет доступа к списку комнат, к которым он присоединился).

Присоединение и отсоединение

Вы можете вызвать join для подписки сокета на данный канал:

io.on('connection', socket => {
  socket.join('some room');
});

Затем просто используйте to или in (они одинаковы) при трансляции или отправке:

io.to('some room').emit('some event');

Вы можете отправлять события сразу в несколько комнат:

io.to('room1').to('room2').to('room3').emit('some event');

В этом случае выполняется объединение: каждый сокет, который входит хотя бы в одну из комнат, получит событие один раз (даже если сокет находится в двух или более комнатах).

Вы также можете транслировать событие в комнату из определенного сокета:

io.on('connection', function(socket){
  socket.to('some room').emit('some event');
});

В этом случае каждое сокет в комнате исключая отправителя получит событие.

Broadcasting to room excepting the sender

Чтобы покинуть канал, вызывайте leave аналогично join.

Почтовая комната

Каждый Socket в Socket.IO идентифицируется случайным, непредсказуемым, уникальным идентификатором Socket#id. Для удобства каждый сокет автоматически присоединяется к комнате, идентифицированной его собственным идентификатором.

Это упрощает реализацию частных сообщений:

io.on("connection", socket => {
  socket.on("private message", (anotherSocketId, msg) => {
    socket.to(anotherSocketId).emit("private message", socket.id, msg);
  });
});

Примеры использования

  • передача данных каждому устройству/вкладке данного пользователя
io.on('connection', async (socket) => {
  const userId = await fetchUserId(socket);

  socket.join(userId);

  // and then later
  io.to(userId).emit('hi');
});
  • отправка уведомлений об определенном объекте
io.on('connection', async (socket) => {
  const projects = await fetchProjects(socket);

  projects.forEach(project => socket.join('project:' + project.id));

  // and then later
  io.to('project:4321').emit('project updated');
});

Использование с асинхронным кодом

Пожалуйста, используйте io.to(...).emit(...) (или socket.to(...).emit(...)) синхронным образом.

Пример с обратной функцией:

// BAD
const room = socket.to('room1');
saveProduct(() => {
  room.emit('product-updated');
});

// GOOD
saveProduct(() => {
  socket.to('room1').emit('product-updated');
});

Пример с async/await:

// BAD
io.to('room2').emit('details', await fetchDetails());

// GOOD
const details = await fetchDetails();
io.to('room2').emit('details', details);

Пояснение: метод to() не возвращает новый объект, а изменяет атрибут объекта io (соответственно, объекта socket).

Это также относится к другим модификаторам трансляции:

  • local
  • broadcast
  • volatile

Отключение

При отключении сокеты leave автоматически все каналы, в которых они участвовали, и вам не нужно выполнять специальное завершение.

Вы можете получить список комнат, в которых находился сокет, прослушивая событие disconnecting:

io.on('connection', socket => {
  socket.on('disconnecting', () => {
    console.log(socket.rooms); // the Set contains at least the socket ID
  });

  socket.on('disconnect', () => {
    // socket.rooms.size === 0
  });
});

С несколькими серверами Socket.IO

Как и при глобальной трансляции, трансляция в комнаты также работает с несколькими серверами Socket.IO.

Вам просто нужно заменить стандартный адаптер на Redis адаптер. Более подробная информация об этом здесь.

Broadcasting to room with Redis

Подробности реализации

Функция «комната» реализована с помощью того, что мы называем адаптером. Этот адаптер — это компонент на стороне сервера, который отвечает за:

  • хранение отношений между экземплярами сокетов и комнатами
  • трансляцию событий всем (или подмножеству) клиентам

Вы можете найти код стандартного адаптера в памяти здесь.

В основном, он состоит из двух ES6 Map:

  • sids: Map<SocketId, Set<Room>>
  • rooms: Map<Room, Set<SocketId>>

Вызов socket.join("the-room") приведет к:

  • в карте sids, добавлению «the-room» в Set, идентифицируемый ID сокета
  • в карте rooms, добавлению ID сокета в Set, идентифицируемый строкой «the-room»

Затем эти две карты используются при трансляции:

  • трансляция во все сокеты (io.emit()) перебирает карту sids, и отправляет пакет всем сокетам
  • трансляция в определенную комнату (io.to("room21").emit()) перебирает Set в карте rooms, и отправляет пакет всем соответствующим сокетам

Вы можете получить доступ к этим объектам следующим образом:

// main namespace
const rooms = io.of("/").adapter.rooms;
const sids = io.of("/").adapter.sids;

// custom namespace
const rooms = io.of("/my-namespace").adapter.rooms;
const sids = io.of("/my-namespace").adapter.sids;

Примечания:

  • эти объекты не предназначены для непосредственного изменения, вы всегда должны использовать socket.join(...) и socket.leave(...) вместо этого.
  • в конфигурации с несколькими серверами, объекты rooms и sids не разделяются между серверами Socket.IO (комната может «существовать» только на одном сервере, а не на другом).

События комнат

Начиная с socket.io@3.1.0, базовый адаптер будет генерировать следующие события:

  • create-room (аргумент: комната)
  • delete-room (аргумент: комната)
  • join-room (аргумент: комната, id)
  • leave-room (аргумент: комната, id)

Пример:

io.of("/").adapter.on("create-room", (room) => {
  console.log(`room ${room} was created`);
});

io.of("/").adapter.on("join-room", (room, id) => {
  console.log(`socket ${id} has joined room ${room}`);
});

© 2014–2021 Automattic
Licensed under the MIT License.
https://socket.io/docs/v3/rooms

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API