Надійність транспортування через Websocket (втрата даних Socket.io під час повторного підключення)


81

Використовується

NodeJS, Socket.io

Проблема

Уявіть, що є 2 користувачі U1 та U2 , підключені до програми через Socket.io. Алгоритм такий:

  1. U1 повністю втрачає з’єднання з Інтернетом (наприклад, вимикає Інтернет)
  2. U2 надсилає повідомлення на U1 .
  3. U1 ще не отримує повідомлення, оскільки Інтернет не працює
  4. Сервер виявляє відключення U1 за часом очікування серцебиття
  5. U1 знову підключається до socket.io
  6. U1 ніколи не отримує повідомлення від U2 - воно втрачається на кроці 4, я думаю.

Можливе пояснення

Думаю, я розумію, чому це відбувається:

  • на кроці 4 Сервер вбиває екземпляр сокета та чергу повідомлень до U1 , а
  • Більше того, на кроці 5 U1 та сервер створюють нове з'єднання (воно не використовується повторно), тому навіть якщо повідомлення все ще в черзі, попереднє з'єднання все одно втрачається.

Потрібна допомога

Як я можу запобігти такій втраті даних? Я повинен використовувати сердечні ритми, тому що я не вішаю людей у ​​програмі назавжди. Крім того, я все одно повинен надати можливість повторного підключення, тому що коли я розгортаю нову версію програми, я хочу нульових простоїв.

PS Те, що я називаю "повідомленням", - це не просто текстове повідомлення, яке я можу зберігати в базі даних, а цінне системне повідомлення, доставка якого повинна бути гарантована, або інтерфейс, який викручується.

Дякую!


Додаток 1

У мене вже є система облікових записів користувачів. Більше того, моя заявка вже складна. Додавання статусів офлайн / онлайн не допоможе, оскільки я вже маю подібні речі. Проблема в іншому.

Перевірте крок 2. На цьому кроці ми технічно не можемо сказати, якщо U1 переходить в автономний режим , він просто втрачає зв’язок, дозволяє говорити протягом 2 секунд, можливо, через поганий Інтернет. Тож U2 надсилає йому повідомлення, але U1 не отримує його, оскільки Інтернет для нього все ще не працює (крок 3). Крок 4 необхідний для виявлення автономних користувачів, скажімо, час очікування становить 60 секунд. Зрештою ще через 10 секунд підключено Інтернет-з'єднання для U1, і він знову підключається до socket.io. Але повідомлення від U2 втрачається в просторі, оскільки на сервері U1 був відключений через таймаут.

У цьому проблема, я не хочу 100% доставки.


Рішення

  1. Зберіть випромінювання (ім’я та дані випромінювання) у користувача {}, ідентифіковане випадковим emitID. Надіслати випуск
  2. Підтвердьте випромінювання на стороні клієнта (надішліть випромінювання назад на сервер за допомогою emitID)
  3. Якщо підтверджено - видаліть об’єкт із {}, ідентифікований emitID
  4. Якщо користувач повторно підключений - перевірте {} для цього користувача та пройдіть його, виконуючи крок 1 для кожного об’єкта в {}
  5. При відключенні або / та підключеному змиванні {} для користувача, якщо це необхідно
// Server
const pendingEmits = {};

socket.on('reconnection', () => resendAllPendingLimits);
socket.on('confirm', (emitID) => { delete(pendingEmits[emitID]); });

// Client
socket.on('something', () => {
    socket.emit('confirm', emitID);
});

Рішення 2 (певне)

Додано 1 лютого 2020 р.

Незважаючи на те, що це насправді не рішення для Websockets, комусь все одно це може стати в нагоді. Ми перейшли з Websockets на SSE + Ajax. SSE дозволяє підключатися від клієнта, щоб підтримувати постійне TCP-з'єднання та отримувати повідомлення від сервера в режимі реального часу. Щоб надсилати повідомлення від клієнта на сервер - просто використовуйте Ajax. Є такі недоліки, як затримка та накладні витрати, але SSE гарантує надійність, оскільки це TCP-з'єднання.

Оскільки ми використовуємо Express, ми використовуємо цю бібліотеку для SSE https://github.com/dpskvn/express-sse , але ви можете вибрати ту, яка вам підходить.

SSE не підтримується в IE та більшості версій Edge, тому вам знадобиться поліфіл: https://github.com/Yaffle/EventSource .


Правда, що. Але socket.io насправді є лише транспортним протоколом. Він сам по собі не може гарантувати послідовну та надійну доставку повідомлень. Вам слід переглянути (і прочитати) архітектури pub-sub (опублікувати-підписатись) та черги повідомлень. На практиці ви будете використовувати стійку базу даних, наприклад redis, для зберігання повідомлень.
user568109

Тож pubsub вирішить це питання? Якщо ви напишете вичерпну відповідь і рішення спрацює, ви отримаєте винагороду (50 балів).
ігорпавлов

8
таке прекрасно організоване запитання
Кеті

1
Дякую. Треба сказати, що прийнята відповідь працює для мене. На даний момент я використовую запропоновану схему і не маю проблем.
igorpavlov 05.03.14

Привіт Ігоре! Я новачок у Node.js та Socket.io. Якщо це можливо, не могли б ви показати свій код :)
Eazy

Відповіді:


102

Інші натякали на це в інших відповідях та коментарях, але корінна проблема полягає в тому, що Socket.IO - це просто механізм доставки, і ви не можете покладатися лише на нього для надійної доставки. Єдина людина, яка точно знає, що повідомлення було успішно доставлено клієнту, - це сам клієнт . Для такого роду систем я б рекомендував зробити такі твердження:

  1. Повідомлення не надсилаються безпосередньо клієнтам; натомість вони надсилаються на сервер і зберігаються в якомусь сховищі даних.
  2. Клієнти несуть відповідальність за запитання "що я пропустив" при повторному підключенні та запитуємо збережені повідомлення в сховищі даних, щоб оновити їх стан.
  3. Якщо повідомлення надсилається на сервер, коли підключений клієнт-одержувач, це повідомлення буде надіслано клієнту в режимі реального часу.

Звичайно, залежно від потреб вашого додатку, ви можете налаштувати ці частини - наприклад, ви можете використовувати, скажімо, список Redis або відсортований набір для повідомлень, і очистити їх, якщо ви знаєте, що клієнт уже готовий на сьогоднішній день.


Ось кілька прикладів:

Щасливий шлях :

  • U1 і U2 підключені до системи.
  • U2 надсилає на сервер повідомлення, яке U1 має отримати.
  • Сервер зберігає повідомлення в якомусь постійному сховищі, позначаючи його для U1 якоюсь міткою часу або послідовним ідентифікатором.
  • Сервер надсилає повідомлення на U1 через Socket.IO.
  • Клієнт U1 підтверджує (можливо, через зворотний дзвінок Socket.IO), що отримав повідомлення.
  • Сервер видаляє збережене повідомлення із сховища даних.

Офлайн-шлях :

  • U1 втрачає підключення до Інтернету.
  • U2 надсилає на сервер повідомлення, яке U1 має отримати.
  • Сервер зберігає повідомлення в якомусь постійному сховищі, позначаючи його для U1 якоюсь міткою часу або послідовним ідентифікатором.
  • Сервер надсилає повідомлення на U1 через Socket.IO.
  • Клієнт U1 не підтверджує отримання, оскільки він офлайн.
  • Можливо, U2 надсилає U1 ще кілька повідомлень; всі вони зберігаються в сховищі даних однаково.
  • Коли U1 підключається знову, він запитує сервер "Останнє повідомлення, яке я бачив, було X / У мене є стан X, що я пропустив".
  • Сервер надсилає U1 всі повідомлення, які він пропустив із сховища даних, на основі запиту U1
  • Клієнт U1 підтверджує отримання, а сервер видаляє ці повідомлення із сховища даних.

Якщо ви абсолютно бажаєте гарантованої доставки, тоді важливо спроектувати свою систему таким чином, щоб підключення насправді не мало значення, а доставка в режимі реального часу - це просто бонус ; це майже завжди включає в себе якийсь сховище даних. Як зазначив user568109 у коментарі, існують системи обміну повідомленнями, які абстрагують зберігання та доставку зазначених повідомлень, і, можливо, варто розглянути таке попередньо побудоване рішення. (Ймовірно, вам все одно доведеться писати інтеграцію Socket.IO самостійно.)

Якщо ви не зацікавлені в зберіганні повідомлень у базі даних, можливо, вам вдасться піти, зберігаючи їх у локальному масиві; сервер намагається надіслати повідомлення U1 і зберігає його у списку "повідомлень, що очікують на розгляд", доки клієнт U1 не підтвердить, що отримав його. Якщо клієнт перебуває в автономному режимі, тоді, коли він повернеться, він може сказати серверу "Гей, я був відключений, будь ласка, надішліть мені все, що я пропустив", і сервер може переглядати ці повідомлення.

На щастя, Socket.IO забезпечує механізм, який дозволяє клієнту "відповідати" на повідомлення, яке виглядає як власний зворотний виклик JS. Ось псевдокод:

// server
pendingMessagesForSocket = [];

function sendMessage(message) {
  pendingMessagesForSocket.push(message);
  socket.emit('message', message, function() {
    pendingMessagesForSocket.remove(message);
  }
};

socket.on('reconnection', function(lastKnownMessage) {
  // you may want to make sure you resend them in order, or one at a time, etc.
  for (message in pendingMessagesForSocket since lastKnownMessage) {
    socket.emit('message', message, function() {
      pendingMessagesForSocket.remove(message);
    }
  }
});

// client
socket.on('connection', function() {
  if (previouslyConnected) {
    socket.emit('reconnection', lastKnownMessage);
  } else {
    // first connection; any further connections means we disconnected
    previouslyConnected = true;
  }
});

socket.on('message', function(data, callback) {
  // Do something with `data`
  lastKnownMessage = data;
  callback(); // confirm we received the message
});

Це дуже схоже на останню пропозицію, просто без постійного сховища даних.


Вас також може зацікавити концепція джерела подій .


2
Я чекав остаточної вичерпної відповіді із заявою, що клієнти ПОВИННІ підтвердити доставку. Здається, насправді немає іншого шляху.
igorpavlov

Щасливі, що допомогли! Дайте мені пінг, якщо у вас є питання.
Мішель Тіллі

Це буде працювати в режимі приватного чату. що відбувається в приміщеннях приміщення, де повідомлення надсилається декільком користувачам. broadcast / socket.in не підтримують зворотний дзвінок. так як ми впораємося з цією ситуацією? моє запитання з цього приводу. ( stackoverflow.com/questions/43186636/… )
jit

2

Відповідь Мішель є досить суттєвою, але є кілька інших важливих речей, які слід врахувати. Основне питання, яке слід задати собі: "Чи є різниця між користувачем та сокетом у моєму додатку?" Інший спосіб запитати: "Чи може кожен зареєстрований користувач мати одночасно більше 1 сокетного з'єднання?"

У веб-світі, ймовірно, завжди є можливість, що один користувач має кілька підключень до сокетів, якщо ви спеціально не встановили щось на місці, що запобігає цьому. Найпростіший приклад цього - якщо у користувача відкрито дві вкладки однієї сторінки. У цих випадках ви не дбаєте про те, щоб надіслати повідомлення / подію користувачеві-користувачеві лише один раз ... вам потрібно надіслати його кожному екземпляру сокета для цього користувача, щоб кожна вкладка могла запускати свої зворотні виклики для оновлення стану інтерфейсу користувача. Можливо, це не турбує певні програми, але, як я вважаю, це стосується більшості. Якщо вас це турбує, читайте далі ....

Для вирішення цієї проблеми (якщо ви використовуєте базу даних як постійне сховище) вам знадобляться 3 таблиці.

  1. користувачів - це 1: 1 для реальних людей
  2. клієнтів - що представляє "вкладку", яка може мати єдине підключення до сервера сокетів. (будь-який "користувач" може мати декілька)
  3. повідомлення - повідомлення, яке потрібно надіслати клієнту (не повідомлення, яке потрібно надіслати користувачеві або сокету)

Таблиця користувачів є необов’язковою, якщо ваша програма цього не вимагає, але ОП повідомив, що вона є.

Інше, що потрібно правильно визначити, це "що таке підключення до сокета?", "Коли створюється підключення до сокета?", "Коли підключення до сокета використовується повторно?". Псевдокод Мішель здається, що сокетне з'єднання можна використовувати повторно. З Socket.IO їх НЕ МОЖЕ повторно використовувати. Я бачив, що це джерело великої плутанини. Є сценарії реального життя, коли приклад Мішель має сенс. Але я повинен уявити, що ці сценарії трапляються рідко. Що насправді відбувається, це те, коли сокетне з’єднання втрачено, це з’єднання, ідентифікатор тощо ніколи не буде використано повторно. Тож будь-які повідомлення, позначені для цього сокета, ніколи нікому не доставлятимуться, тому що коли клієнт, який спочатку підключився, підключається повторно, він отримує абсолютно нове з’єднання та новий ідентифікатор. Це означає

Отже, для веб-прикладу тут буде набір кроків, які я рекомендую:

  • Коли користувач завантажує клієнта (як правило, одну веб-сторінку), що має потенціал для створення підключення до сокета, додайте рядок до бази даних клієнтів, який пов’язаний з їх ідентифікатором користувача.
  • Коли користувач насправді підключається до сервера сокетів, передайте ідентифікатор клієнта серверу із запитом на підключення.
  • Сервер повинен перевірити, чи дозволено користувачеві підключатися, а рядок клієнта в таблиці клієнтів доступний для підключення та відповідно дозволити / заборонити.
  • Оновіть рядок клієнта за допомогою ідентифікатора сокета, згенерованого Socket.IO.
  • Надішліть будь-які елементи в таблиці повідомлень, підключені до ідентифікатора клієнта. При початковому підключенні їх не було б, але якщо це було від клієнта, який намагався відновити зв’язок, то можуть бути.
  • Щоразу, коли повідомлення потрібно надіслати до цього сокета, додайте рядок у таблиці повідомлень, який пов’язаний із ідентифікатором клієнта, який ви створили (а не ідентифікатором сокета).
  • Спробуйте видати повідомлення та вислухати клієнта з підтвердженням.
  • Отримавши підтвердження, видаліть цей елемент із таблиці повідомлень.
  • Можливо, ви захочете створити певну логіку на стороні клієнта, яка відкидає дублікати повідомлень, надісланих із сервера, оскільки це технічно можливо, як зазначали деякі.
  • Потім, коли клієнт відключається від сервера сокетів (цілеспрямовано або через помилку), НЕ видаляйте рядок клієнта, просто очистіть ідентифікатор сокета максимум. Це тому, що той самий клієнт міг спробувати відновити зв’язок.
  • Коли клієнт намагається відновити зв’язок, надішліть той самий ідентифікатор клієнта, який він надіслав із початковою спробою підключення. Сервер буде розглядати це так само, як початкове з'єднання.
  • Коли клієнт знищений (користувач закриває вкладку або відходить), це коли ви видаляєте рядок клієнта та всі повідомлення для цього клієнта. Цей крок може бути трохи складним.

Оскільки останній крок хитрий (принаймні раніше, я давно нічого подібного не робив) і тому, що бувають випадки, як втрата потужності, коли клієнт відключається, не очищаючи рядок клієнта, і ніколи не намагається щоб відновити зв’язок із тим самим рядком клієнта - ви, ймовірно, хочете мати щось, що періодично запускається для очищення будь-яких застарілих рядків клієнта та повідомлень. Або ви можете назавжди назавжди зберігати всіх клієнтів та повідомлення та просто відповідним чином позначати їх стан.

Тож, щоб було зрозуміло, у випадках, коли у одного користувача відкрито дві вкладки, ви додасте два однакові повідомлення до таблиці повідомлень, кожна з яких позначена для іншого клієнта, оскільки ваш сервер повинен знати, чи отримав їх кожен клієнт, а не лише кожен користувач.


1

Здається, у вас вже є система облікових записів користувачів. Ви знаєте, який обліковий запис знаходиться в Інтернеті / в автономному режимі, Ви можете обробляти подію підключення / відключення:

Отже, рішення полягає в тому, щоб додати в базу даних повідомлення в режимі онлайн / офлайн та офлайн для кожного користувача:

chatApp.onLogin(function (user) {
   user.readOfflineMessage(function (msgs) {
       user.sendOfflineMessage(msgs, function (err) {
           if (!err) user.clearOfflineMessage();
       });
   })
});

chatApp.onMessage(function (fromUser, toUser, msg) {
   if (user.isOnline()) {
      toUser.sendMessage(msg, function (err) {
          // alert CAN NOT SEND, RETRY?
      });
   } else {
      toUser.addToOfflineQueue(msg);
   }
})

Будь ласка, прочитайте розділ "Додаток 1" у моєму запитанні. Я не думаю, що ваша відповідь є рішенням.
igorpavlov

Це цікаво, я зараз починаю свій власний проект чату, можливо, з веб-RTC: ->
damphat

Шахта також на WebRTC. Але в цьому контексті це не має значення. Ах ... Якщо у всіх людей стабільний Інтернет ... Я так розчарований, коли користувачі мають 100 Мбіт / с на Speedtest, але насправді, якщо вони намагаються пінгувати, у них 20% втрат пакетів. Кому потрібен такий Інтернет? =)
igorpavlov

0

Подивіться тут: Опрацюйте перезавантаження браузера socket.io .

Я думаю, ви могли б використати рішення, яке я придумав. Якщо ви модифікуєте його належним чином, він повинен працювати як завгодно.


Це цікаво, я не зміг знайти це питання, але гуглив кілька годин. Подивись!
ігорпавлов

Здається, я вже використовую цей вид архітектури. Це не вирішує точної проблеми, яку я описав.
igorpavlov

0

Я думаю, що ви хочете, це мати багаторазовий сокет для кожного користувача, приблизно так:

Клієнт:

socket.on("msg", function(){
    socket.send("msg-conf");
});

Сервер:

// Add this socket property to all users, with your existing user system
user.socket = {
    messages:[],
    io:null
}
user.send = function(msg){ // Call this method to send a message
    if(this.socket.io){ // this.io will be set to null when dissconnected
        // Wait For Confirmation that message was sent.
        var hasconf = false;
        this.socket.io.on("msg-conf", function(data){
            // Expect the client to emit "msg-conf"
            hasconf = true;
        });
        // send the message
        this.socket.io.send("msg", msg); // if connected, call socket.io's send method
        setTimeout(function(){
            if(!hasconf){
                this.socket = null; // If the client did not respond, mark them as offline.
                this.socket.messages.push(msg); // Add it to the queue
            }
        }, 60 * 1000); // Make sure this is the same as your timeout.

    } else {
        this.socket.messages.push(msg); // Otherwise, it's offline. Add it to the message queue
    }
}
user.flush = function(){ // Call this when user comes back online
    for(var msg in this.socket.messages){ // For every message in the queue, send it.
        this.send(msg);
    }
}
// Make Sure this runs whenever the user gets logged in/comes online
user.onconnect = function(socket){
    this.socket.io = socket; // Set the socket.io socket
    this.flush(); // Send all messages that are waiting
}
// Make sure this is called when the user disconnects/logs out
user.disconnect = function(){
    self.socket.io = null; // Set the socket to null, so any messages are queued not send.
}

Тоді черга сокетів зберігається між роз'єднаннями.

Переконайтеся, що воно зберігає кожну socketвластивість користувачів у базі даних і зробіть методи частиною вашого прототипу користувача. База даних не має значення, просто збережіть її, однак ви зберігали своїх користувачів.

Це дозволить уникнути проблеми, згаданої в Additon 1, вимагаючи підтвердження від клієнта перед позначенням повідомлення як відправленого. Якщо ви дійсно хотіли, ви можете дати кожному повідомленню ідентифікатор і попросити клієнта надіслати ідентифікатор повідомлення msg-conf, а потім перевірити його.

У цьому прикладі user- це шаблон користувача, з якого копіюються всі користувачі, або подібний користувацькому прототипу.

Примітка: Це не перевірено.


Чи можете ви сказати мені, що насправді є змінною "користувач"?
igorpavlov

Насправді, я думаю, ти забив моє запитання. Але чи можете ви, будь-ласка, надати деякі коментарі до кожного фрагмента коду? Я ще не розумію, як я можу інтегрувати це в свій код. Також де я повинен зберігати його в базі даних і яку базу даних ви маєте на увазі? Редіс чи може бути Монго чи не має значення?
igorpavlov

Це все ще не вирішує проблему. Коли повідомлення відправляється, обидва користувачі (відправник і одержувач) працюють в режимі он-лайн для сервера. Будь ласка, уважно прочитайте Додаток 1 до мого запитання. У цьому випадку "this.socket.io" завжди буде "true", тому повідомлення надсилається, але не отримується. Ви намагаєтесь вирішити проблему, коли SENDER переходить в автономний режим, але не отримує. Або я не правий?
igorpavlov

@igorpavlov, Вибачте, але ви мене нерозумієте. Уявіть собі: U1 хоче послати повідомлення «Привіт» для U2: users.getUserByName("U2").send("Hi"). Тоді, якщо U2 в мережі, socket.io U2 не буде нульовим, тому повідомлення буде надіслано. Якщо сокет U2 нульовий, він буде в черзі, поки U2 не з’явиться в мережі.
Арі Порад

1
Я вважаю, що @igorpavlov має рацію. Буде певний проміжок часу, коли клієнт буде фактично відключений, але сервер цього не знає, оскільки серцебиття ще не сталося. У цей період часу this.socket.ioцього не буде null, і сервер спробує доставити повідомлення.
Michelle Tilley

0

Як вже було написано в іншій відповіді, я також вважаю, що ви повинні дивитися на реальний час як на бонус: система повинна мати можливість працювати також без реального часу.

Я розробляю корпоративний чат для великої компанії (ios, android, web frontend та .net core + postGres backend) і після того, як розробив спосіб для веб-сокета відновити з’єднання (через сокет uuid) і отримувати недоставлені повідомлення (зберігається в черзі) Я зрозумів, що є краще рішення: повторна синхронізація через API відпочинку.

В основному я закінчив, використовуючи websocket лише для реального часу, з цілочисельним тегом на кожному повідомленні в реальному часі (користувач в мережі, типи, повідомлення чату тощо) для моніторингу втрачених повідомлень.

Коли клієнт отримує ідентифікатор, який не є монолітним (+1), він розуміє, що він не синхронізований, тому скидає всі повідомлення сокета і просить повторну синхронізацію всіх своїх спостерігачів через REST api.

Таким чином, ми можемо обробляти багато варіацій стану програми протягом офлайн-періоду, не вимагаючи синтаксичного аналізу тонн повідомлень веб-розетки підряд при повторному підключенні, і ми обов’язково будемо синхронізовані (оскільки остання дата синхронізації встановлюється саме за допомогою API REST , а не з розетки).

Єдина хитра частина - це моніторинг повідомлень у режимі реального часу з моменту виклику REST api до моменту відповіді сервера, оскільки прочитане з бази даних вимагає часу, щоб повернутися до клієнта, а тим часом можуть траплятися зміни, тому їх потрібно кешувати і врахували.

Ми починаємо виробництво через пару місяців, я сподіваюся до того часу спати :)


-2

Я дивився на ці речі останнім часом і думаю, що інший шлях може бути кращим.

Спробуйте переглянути автобус служби Azure, питання та теми подбайте про стан офлайн. Повідомлення чекає повернення користувача, і тоді вони отримують повідомлення.

Це вартість запуску черги, але це приблизно 0,05 дол. США на мільйон операцій для базової черги, тому вартість розробника буде більшою від години роботи, необхідної для написання системи черги. https://azure.microsoft.com/en-us/pricing/details/service-bus/

А на лазурній шині є бібліотеки та приклади для PHP, C #, Xarmin, Anjular, Java Script тощо.

Отже, сервер надсилає повідомлення і не потрібно турбуватися про їх відстеження. Клієнт може використовувати повідомлення для зворотного відправлення також як засіб для обробки балансування навантаження, якщо це необхідно.


Для мене це схоже на розміщення продукту. Хтось може вважати це корисним, але це навіть не технологія, а ціла послуга, також платна.
igorpavlov

-2

Спробуйте цей список чату

io.on('connect', onConnect);

function onConnect(socket){

  // sending to the client
  socket.emit('hello', 'can you hear me?', 1, 2, 'abc');

  // sending to all clients except sender
  socket.broadcast.emit('broadcast', 'hello friends!');

  // sending to all clients in 'game' room except sender
  socket.to('game').emit('nice game', "let's play a game");

  // sending to all clients in 'game1' and/or in 'game2' room, except sender
  socket.to('game1').to('game2').emit('nice game', "let's play a game (too)");

  // sending to all clients in 'game' room, including sender
  io.in('game').emit('big-announcement', 'the game will start soon');

  // sending to all clients in namespace 'myNamespace', including sender
  io.of('myNamespace').emit('bigger-announcement', 'the tournament will start soon');

  // sending to individual socketid (private message)
  socket.to(<socketid>).emit('hey', 'I just met you');

  // sending with acknowledgement
  socket.emit('question', 'do you think so?', function (answer) {});

  // sending without compression
  socket.compress(false).emit('uncompressed', "that's rough");

  // sending a message that might be dropped if the client is not ready to receive messages
  socket.volatile.emit('maybe', 'do you really need it?');

  // sending to all clients on this node (when using multiple nodes)
  io.local.emit('hi', 'my lovely babies');

};

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.