Socket.io: Несколько сокетов открываются после повторного подключения

Созданный на 28 июл. 2011  ·  54Комментарии  ·  Источник: socketio/socket.io

Я заметил это как в моем приложении socket.io, так и в чьем-то еще. Когда происходит переподключение, обычно открывается более одного сокета на клиенте, чего никогда не должно происходить.

Вот журнал, который я получил из моего собственного тестового приложения, когда у меня было отключение / повторное подключение.

** Отключить* * Повторное соединение с задержкой 1000 попыток: 1
** Повторное подключение с задержкой 2000 попыток: 2* * Подключение с помощью xhr-polling
** Подключение с помощью xhr-polling* * Повторное соединение с транспортным типом xhr-polling Попыток: 2
** Связаны* * Подключено

Когда это происходит, я получаю повторяющиеся сообщения, по одному для каждого подключенного сокета, хотя должно быть только одно. Firebug подтверждает, что на самом деле подключены два сокета от клиента. Я предполагаю, что это в клиентском коде, возможно, это не закрытие первой попытки повторного подключения.

Конечно, настоящий вопрос может заключаться в том, почему вообще произошло отключение?

Socket.IO client bug

Самый полезный комментарий

Изучив это немного дальше, кажется, я нашел причину своих проблем. Это не ошибка , а неправильная реализация клиентского кода с моей стороны. facepalm Это то, что у меня было изначально:

ПРОБЛЕМА:

var socket = io.connect();

socket.on('connect', function () {

  console.log('User connected!');

  socket.on('message', function(message) {

    console.log(message);

  });

});

Вышеупомянутый клиентский JavaScript вызвал множественные вызовы console.log () при повторном подключении клиента (ов). Это то, что я заменил на:

РЕШЕНИЕ:

var socket = io.connect();

socket.on('connect', function () {

  console.log('User connected!');

});

socket.on('message', function(message) {

  console.log(message);

});

Теперь несколько сообщений не отправляются туда и обратно, когда клиенты повторно подключаются к серверу. Может ли кто-нибудь еще подтвердить, что изменение кода на стороне клиента устраняет проблему?

Все 54 Комментарий

Отключение запускается, потому что технически клиент отключился от сервера. И отключается до тех пор, пока событие повторного подключения не будет запущено снова.

Но в остальном - ошибка.

Я думаю, что это причина ошибки и в моем приложении -

На стороне сервера я создал настраиваемый курсор на mongodb, который срабатывает каждый раз, когда появляется новая вставка. Затем это сообщение отправляется через io.sockets.emit () всем подключенным.

Но вместо того, чтобы получать только одно сообщение на событие, я получаю несколько повторяющихся сообщений на стороне клиента.

У меня крайне ненадежное интернет-соединение, поэтому я предполагаю, что эта ошибка влияет и на мой код.

Вы, ребята, использовали expressjs? У меня была эта проблема с экспрессом, переписал без, и все заработало.

Express не имел бы никакого отношения к этому @mfkp , должно быть, делал что-то странное

Согласен с @visionmedia , это ошибка в socket.io, а не в Express. Поскольку текущая реализация повторного подключения по-прежнему была разработана для версии 0.6, поэтому в ней отсутствуют некоторые проверки и чистки.

Ах я вижу. Да ладно, продолжай ;-)

+1 к этому. Периодическая проблема в нашем приложении чата, когда socket.io открывает несколько подключений. Затем клиент получает дубли всех излучений.

+1. Веб-сокеты и хром. Ноутбук переходит в режим сна -> приложение повторно подключается после пробуждения -> двойные события. Происходит только при подключении к удаленному серверу. Невозможно воспроизвести это локально, должна быть проблема с повторным подключением / задержкой в ​​сети.

есть ли обходной путь, чтобы избавиться от нескольких подключений после этого? Например, со стороны клиента, если я сделаю socket.disconnect (), он отключит все подключения? Так как хочу избежать многократных обновлений. работает следующее?
socket = io.connect (URL)
socket.on ('подключиться', function () {
if (multipleConnect) {
socket.disconnect ();
socket.removeAllListeners ('подключиться');
io.sockets = {};
socket = io.connect (URL);
socket.on ('подключиться', functionToConnect);
}
})

Пожалуйста, прочтите это https://github.com/LearnBoost/socket.io/issues/474#issuecomment -2833227.
Он объясняет, почему возникает эта ошибка и как ее можно воспроизвести.

@ 3rd-Eden - Есть идеи, где это исправление попадает в ваш список задач / приоритеты? У меня есть приложение, которое я создаю, и я планировал использовать его для него, и хотел бы иметь возможность сообщить своему клиенту, что оно будет правильно повторно подключаться с устройств iOS. Он отключается после перевода приложения в фоновый режим или перевода устройства в спящий режим.

Или у вас есть идеи, как я могу написать обходной путь? Последние пару дней я работал над несколькими вещами, но в лучшем случае всегда кажется, что слишком много соединений остается открытым и теряются все сохраненные данные сокетов. Данные - это не конец света. Я могу использовать триггер повторного подключения от клиента для решения этой проблемы, но одновременные подключения немного уродливы.

Благодаря!

@cris Я не уверен, что это та же ошибка, о которой вы упомянули. У меня есть очень простой пример бага без подтормаживания сервера.

Я могу четко воспроизвести эту проблему:

  1. Реализуйте простой клиент контрольных сигналов, который отправляет контрольные сигналы с интервалом в 1 секунду.
  2. Подсчитайте количество новых подключений на стороне сервера.
  3. Подсчитайте количество отключений на стороне сервера.
  4. Запустите сервер и установите соединение с клиентом.
  5. Разорвать сетевое соединение между клиентом и сервером.
  6. Подождите, пока сервер не истечет и не выдаст событие отключения.
  7. Повторно подключите сетевое соединение.

Обратите внимание на то, что при повторном подключении клиент создает 2-4 подключения, каждое из которых генерирует событие подключения. Сервер получает 2-4 соединения от клиента и генерирует событие «соединение» для каждого. Клиент никогда не закрывает ни одно из неправильно запущенных соединений.

Благодарю. Я действительно считаю, что эта ошибка должна быть приоритетной. Многие коммерческие компании, которые ничего не знают, пытаются нанять людей для разработки на основе socket.io, полагая, что это хорошо работает. Разумеется, socket.io бесплатен, поэтому, возможно, этим коммерческим компаниям стоит обратить внимание на коммерческие продукты. Но опять же, я думаю, что это действительно нужно сделать очень приоритетным. Эта ошибка существует с версии 0.7.0 и легко воспроизводима.

@davidfooks , @theyak. Я давно исправил эту проблему, и она работает без проблем.

Для исправления необходимо:

  1. Примените этот патч: https://github.com/LearnBoost/socket.io-client/pull/342
  2. Отключите AJAX-рукопожатие (и пусть рукопожатие будет только через JSONP), как описано в комментарии к запросу на вытягивание.

Как отключить рукопожатие AJAX? Я предполагаю, что вы все еще можете использовать все типы подключения, это повлияет только на рукопожатие?

+1 исправьте пожалуйста :)

У меня было такое же множественное подключение при повторном подключении. Я считаю, что это серьезная проблема ...
Причина в том, что вызывается метод Socket.connect, но флаг conneting устанавливается в значение true только после завершения рукопожатия, в случае, если один из таймеров matbeReconnect (таймеры, обрабатывающие повторное подключение) просыпается во время процесса рукопожатия, они вызовут Socket. подключиться снова, вызывая несколько повторных подключений.
Я решил проблему, вызвав self.reconnecting в начале метода Socket.connect.

Есть ли шанс слить это?
Эта ошибка также является плохой ошибкой в ​​моем приложении.

Эта ошибка все еще существует. Пробовал оба патча. Безуспешно.

+1 У меня эта проблема часто возникает при использовании xhr-polling, патчи еще не пробовал

+1, у меня тоже такая проблема с дублирующими переподключениями.

Каждый раз, когда Node.js перезапускается (то есть при запуске через супервизор), мой клиент (ы) повторно подключается в X раз, сколько раз Node.js был перезапущен с точки, к которой клиент (ы) подключился изначально. Ошибка приводит к тому, что события генерируются один раз при повторном подключении со стороны клиента - это не просто вопрос дубликатов.

Я попробовал socket.on('disconnect', function() { socket.disconnect(); }); на стороне клиента, но это не сработало. : /

Изучив это немного дальше, кажется, я нашел причину своих проблем. Это не ошибка , а неправильная реализация клиентского кода с моей стороны. facepalm Это то, что у меня было изначально:

ПРОБЛЕМА:

var socket = io.connect();

socket.on('connect', function () {

  console.log('User connected!');

  socket.on('message', function(message) {

    console.log(message);

  });

});

Вышеупомянутый клиентский JavaScript вызвал множественные вызовы console.log () при повторном подключении клиента (ов). Это то, что я заменил на:

РЕШЕНИЕ:

var socket = io.connect();

socket.on('connect', function () {

  console.log('User connected!');

});

socket.on('message', function(message) {

  console.log(message);

});

Теперь несколько сообщений не отправляются туда и обратно, когда клиенты повторно подключаются к серверу. Может ли кто-нибудь еще подтвердить, что изменение кода на стороне клиента устраняет проблему?

Привет. Я была такая же проблема. Когда я перезапускал узел (или когда время ожидания соединения истекло) и клиент повторно подключился, я получал то же сообщение, которое сервер отправлял за n раз (где n было количеством повторных подключений).
Я решил эту проблему, переместив все свои обработчики из socket.on ('connect' function () {...}); функция вне его.

Приведенный выше код делает то, что нужно.
Это мой полный ответ из списка рассылки:
https://groups.google.com/forum/?hl=en&fromgroups#!topic/socket_io/X9FRMjCkPco

@xdanx ,

да, мне кажется, что это тоже работает: поместить код socket.on ('message') отдельно от кода события 'connect'

А как же «Связь»?
А как насчет объекта "сокет" в обратном вызове?

/ edit Nevermind, я вижу, «connect» находится на клиенте. У меня все еще возникала проблема с рассылкой спама при повторном подключении, когда я этого не делал. Но это было в 0.9.6

Кажется, у меня такая же проблема ... Пробовал описанное выше исправление перемещения кода сообщения в отдельные блоки ... но заметил, что у меня никогда не было этого вместе.

есть новости о других решениях для этого в 0.9.8?

У меня та же проблема. У меня установлена ​​0.9.10. Как это исправить? :(
кстати, это было более года назад, и пока нет исправлений .. :(

РЕДАКТИРОВАТЬ.

Кажется, проблема исчезла, когда я использую только jsonp-polling.
io.set ('транспорты', ['jsonp-polling']);

У меня та же проблема.
разъем. [email protected]
узел v0.8.8

@semprom Я думаю, что использование jsonp-polling исправляет это, потому что это может относиться только к соединениям websocket.

К сожалению, для меня вся моя реализация полагается на то, что обратная связь будет как можно быстрее, поэтому веб-сокеты, а не опрос, работают лучше всего, и поскольку я контролирую подключенных клиентов, я не вижу причин, кроме этой проблемы, переходить к чему-либо еще.

Обратите внимание, что несколько подключений от одного и того же повторно подключающегося клиента имеют одинаковые socket.id . Таким образом, вы можете вести собственный список идентификаторов сокетов и игнорировать дубликаты, чтобы обойти эту проблему.

@KasperTidemann Спасибо. Это решило эту проблему.

@esanai Без проблем, рад, что это сработало!

Привет, у меня такая же проблема, и я заметил, что каждый раз, когда соединение восстанавливается, создается новый идентификатор клиентского сокета. Решение - использовать io.set ('transports', ['jsonp-polling']); или использовать решение KasperTidemann?

@KasperTidemann Боже мой, чувак, это именно ответ на мои проблемы! См. Этот коммит: https://github.com/samuelclay/NewsBlur/commit/76cbbd8d8b2a787985bba724dc3562108492b017#L2L3887

Я могу воспроизвести событие двойного подключения после ошибки подключения по желанию с помощью этого простого клиентского и серверного кода в одном файле node.js:

"use strict";

var server = require('socket.io');
var client = require('socket.io-client');

setTimeout(function () {
    var io = server.listen(8888);

    io.of('/chat').on('connection', function (socket) {
        console.log('Server: /chat connection');
        socket.emit('greeting', 'Hello, who are you?');
    });

    io.sockets.on('connection', function (socket) {
        console.log('Server: connection');
    });
}, 2000);

var socketAddress = 'http://localhost:8888/chat';
var socket = client.connect(socketAddress);

socket.on('connect', function () {
    console.log("Client: connect");
});

socket.on('greeting', function (data) {
    console.log("Client: greeting: ", data);
});

socket.on('error', function () {
    console.log("Client: error");
    socket.socket.reconnect();
});

Какие-нибудь исправления не видны?

Извините, я также разместил это в выпуске № 474.

Я могу воспроизвести эту ошибку довольно последовательно, используя iPhone с iOS 9.3.2 и Chrome версии 50.0.2661.95 и в Safari для iOS с версией 1.4.6 Socket.IO

Я могу воспроизвести это только на мобильном телефоне, и моя страница зависает при запросе на socket.io.

У меня есть простой .on ('connect', function (socket) {console.log ('Connected');}); и он регистрирует Connected дважды, когда возникает ошибка, что заставляет меня думать, что он пытается открыть несколько сокетных соединений одновременно.

screenshot 2016-05-27 13 03 44

Кто-нибудь знает обходной путь для этого?

Почему закрыли этот вопрос ??

В моем примере кода от 14 апреля 2014 г. выше больше не создаются события двойного соединения. Есть событие подключения для '/ chat' и одно для самого сокета. Что кажется разумным.

Также больше нет ошибки даже в клиенте.

Это с socket.io 1.4.8 и node 6.3.0.

Эта ошибка влияет на меня, банкомат.

Очевидно, когда обработчики socket_handler размещены внутри маршрутов, они вызываются несколько раз. Используйте соединение сокета в app.js и требуйте обработчиков внутри соединения сокета, передайте сокет в качестве параметра. Обратите внимание, что некоторые свойства могут не поставляться вместе с экземпляром сокета.

@leemlwando, при необходимости, откройте новый выпуск.

У меня была та же проблема, что и я, - это сделать функцию переподключения вручную на клиенте и вызвать io.destroy (); внутри функции повторного подключения это устранило проблему.

Большое спасибо @leemlwando Ваш последний комментарий заставил меня решить мои проблемы.

Я все еще получаю эту ошибку, есть ли обновление?

Я думаю, что единственная реальная ошибка здесь заключается в том, что в Интернете полно плохого примера кода, в котором вызовы socket.on () заключены в обработчик socket.on ('connect'). Каждый раз, когда сокет повторно подключается, новые экземпляры обработчиков складываются поверх существующих, и это приводит к множественным вызовам для каждого события. Не делайте этого: см. Ответ @KasperTidemann от 25 июля 2012 г.

Возможно, DrLexO, за исключением кода, который я представил выше, продемонстрировал проблему. У него нет socket.on (), заключенного в какой-либо обработчик socket.on ('connect').

Спустя столько лет я удивился, узнав об этой ошибке. Я понятия не имею, все это в порядке или нет. Мне нужно попробовать еще раз?

@KasperTidemann спасибо, проблема действительно решена.

Как вы можете определить своих слушателей событий _ снаружи_ слушателя connect если у вас нет доступа к socket ?

const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);

io.on('connect', function(socket) {

  // only now that we are inside the connect callback do we have access to the socket

  socket.on('join', function(room, user) {
  });

  socket.on('add_message', function(room, user) {
  });

  socket.on('disconnect', function(room, user) {
  });
});

Кажется, люди предлагают, чтобы слушатели событий ( join , add_message и disconnect ) жили независимо, _ вне_ слушателя connect , но как это возможно без socket определяется?

io.on('connect', function(socket) {
  // socket is only available here
});

// socket is undefined here

socket.on('join', function(room, user) {
});

socket.on('add_message', function(room, user) {
});

socket.on('disconnect', function(room, user) {
});

Есть ли другой способ создать экземпляр socket чтобы это было возможно?

Почему это закрыто? @ michael-lynch имеет действительную точку

Я также хотел бы узнать ответ на вопрос @ michael-lynch.

@ DrLex0 на примере веб-сайта socket.io он даже показывает, что он выполняет следующие действия:

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});
Была ли эта страница полезной?
0 / 5 - 0 рейтинги