Ограничение соединения SignalR и браузера - программирование
Подтвердить что ты не робот

Ограничение соединения SignalR и браузера

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

Моя проблема в том, что если я открою одну и ту же страницу на двух разных вкладках (сделал это в Chrome), первая страница загрузится нормально, но вторая страница не вызовет функции сервера - ТОЛЬКО, если я закрою первую страницу.

Итак, насколько я понимаю, это, вероятно, ограничение соединения, связанное с браузером, который не позволяет SignalR подключаться более одного раза (фактически два, один для приема и один для отправки)

Обновление. Я обнаружил, что другие вкладки открыты, но теперь я проверил его, и он позволяет активным показывать только 4 вкладки/pages с подключением. Если я попытаюсь поместить одну и ту же страницу на новую вкладку, никакие данные не будут отправлены, когда я закрою одну из других вкладок, новая вкладка сразу отправит данные.

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

Я не считаю, что это имеет какое-то отношение к IIS, потому что из того, что я знаю, он может принимать тысячи подключений.

4b9b3361

Ответ 1

Эта проблема будет лучше всего решена будущей спецификацией Channel Messaging, которая не была реализована никакими браузерами на сегодняшний день, но мне удалось решить его ограничение количества подключений, как описано Алексом Фордом, и использовать localStorage в качестве шины сообщений между вкладками.

Событие storage позволяет вам распространять данные между вкладками, сохраняя при этом единственное соединение SignalR (тем самым предотвращая насыщение соединения). Вызов localStorage.setItem('sharedKey', sharedData) приведет к событию storage во всех других вкладках (не вызывающем):

$(window).bind('storage', function (e) {
    var sharedData = localStorage.getItem('sharedKey');
    if (sharedData !== null)
        console.log(
            'A tab called localStorage.setItem("sharedData",'+sharedData+')'
        );
});

Вы можете проверить if ($.connection.hub.state === 1), чтобы определить, должна ли данная вкладка уведомлять другие вкладки через localStorage (любезно предоставлена ​​Алексом), чтобы предотвратить дублирование вызовов localStorage.setItem.

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

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

Старые подключения: В решении Alex вы должны быть осторожны с Disconnect(), не вызываемым (например, исключение), и вы заполняете свой ковш HubConnections (или репозиторий) старым центром соединения. Если идентификатор сеанса не изменяется (может случиться), это может помешать новым клиентам устанавливать соединение SignalR, хотя ни один из них не активен. В качестве альтернативы, отметьте новые соединения и скопируйте их, чтобы свести к минимуму потенциальное воздействие.

Блокировка: localStorage может быть подвергнута условиям гонки, поскольку она не реализует никакой блокировки как описанной здесь.

Чтобы поддерживать различные типы событий, вы должны закодировать eventType в своих сообщениях JSON и протестировать его в событии storage.

откаты

Если соединение SignalR не может быть установлено, я возвращаюсь на опрос сервера каждые 45 секунд, чтобы получить количество уведомлений.

Если вы не хотите использовать localStorage, вы можете использовать файлы cookie, но это не так чисто.

Ответ 2

Чтобы расширить ответ на @FreshCode, вот как я реализовал его идею.

Мне нужно было выполнить два разных действия между вкладками. Я могу либо установить уведомления, либо удалить уведомления. Эти уведомления принимаются браузером и сохраняются как таймауты, которые будут срабатывать в указанное время. Первая вкладка имеет соединение SignalR, а все остальные - нет. Одна из проблем, которые мне пришлось преодолеть, заключалась в том, что событие "хранения" будет срабатывать независимо от того, какое действие я намерен выполнять (установить/удалить).

То, что я закончил, - это передать пользовательский объект JSON с свойством, содержащим действие, которое я хотел выполнить:

$(window).bind('storage', function () {
    var updateInfo = JSON.parse(localStorage.getItem('updateInfo'));
    if (updateInfo.action == 'removeNotification')
        removeNotification(updateInfo.notificationId);
    else if (updateInfo.action == 'setNotification')
        setNotification(updateInfo.notification);
});

Таким образом, каждый раз, когда я устанавливаю элемент в локальном хранилище, я просто указываю действие, которое должно произойти, и только это действие произойдет на других вкладках. Например, если я обновляю уведомление, это комбинация обоих действий, когда клиент получает его. Он удаляет уведомление и устанавливает уведомление с обновленными значениями. Таким образом, выполняются два вызова localStorage.setItem.

function removeNotification(id) {
    // Check if signalR is connected. If so, I am the tab that will update
    // the other tabs.
    if ($.connection.hub.state === 1) {
        var updateInfo = {
            action: 'removeNotification',
            notificationId: id
        };
        localStorage.setItem('updateInfo', JSON.stringify(updateInfo));
    }
    // brevity brevity
}

Аналогично, функция setNotification.

function setNotification(notification) {
    if ($.connection.hub.state === 1) {
        var updateInfo = {
            action: 'setNotification',
            notification: notification
        };
        localStorage.setItem('updateInfo', JSON.stringify(updateInfo));
    }
    // brevity brevity
}

Ответ 3

Я создал IWC-SignalR, которая позволяет иметь одно соединение SignalR для всех окон (вкладок) одного и того же приложения.

Как это работает

Одно из окон становится владельцем соединения (выбирается случайным образом) и содержит реальное соединение SignalR. Если владелец соединения закрыт или разбился, другое окно становится владельцем соединения - это происходит автоматически. Межконтекстная связь осуществляется с помощью межконтекстной коммуникационной библиотеки (на основе localStorage). Эта библиотека обеспечивает функциональность для связи между окнами между параллельными процессами (блокировки, общие данные, шина событий...). Надеюсь, что это будет полезно для кого-то.