Поделиться через


Общие сведения и обработка событий времени существования подключений в SignalR

Предупреждение

Эта документация не подходит для последней версии SignalR. Взгляните на ASP.NET Core SignalR.

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

В статье предполагается, что у вас уже есть некоторые знания о событиях времени существования SignalR и подключений. Общие сведения о SignalR см. в разделе "Введение в SignalR". Список событий времени существования подключения см. в следующих ресурсах:

Версии программного обеспечения, используемые в этом разделе

Предыдущие версии этого раздела

Сведения о более ранних версиях SignalR см. в разделе SignalR более ранних версий.

Вопросы и комментарии

Оставьте отзыв о том, как вы любили это руководство и что мы могли бы улучшить в комментариях в нижней части страницы. Если у вас есть вопросы, которые не связаны напрямую с руководством, вы можете опубликовать их на форуме ASP.NET SignalR или StackOverflow.com.

Обзор

Эта статья состоит из следующих разделов:

Ссылки на справочные разделы API — это версия API .NET 4.5. Если вы используете .NET 4, ознакомьтесь с версией .NET 4 раздела API.

Терминология и сценарии времени существования подключения

Обработчик OnReconnected событий в Концентраторе SignalR может выполняться непосредственно после OnConnected , но не после OnDisconnected данного клиента. Причина повторного подключения без отключения заключается в том, что в SignalR используется слово "соединение".

Подключения SignalR, подключения транспорта и физические подключения

В этой статье показано, как различать подключения SignalR, подключения транспорта и физические подключения:

  • Подключение SignalR относится к логической связи между клиентом и URL-адресом сервера, поддерживаемым API SignalR и уникальным идентификатором подключения. Данные об этой связи поддерживаются SignalR и используются для установления транспортного подключения. Связь заканчивается и SignalR удаляет данные, когда клиент вызывает Stop метод или ограничение времени ожидания достигается, пока SignalR пытается повторно установить потерянное транспортное подключение.
  • Подключение к транспорту относится к логической связи между клиентом и сервером, поддерживаемыми одним из четырех API транспорта: WebSockets, события, отправленные сервером, навсегда кадр или длинный опрос. SignalR использует API транспорта для создания транспортного подключения, а API транспорта зависит от существования физического сетевого подключения для создания транспортного подключения. Подключение к транспорту заканчивается, когда SignalR завершает его или когда API транспорта обнаруживает, что физическое соединение нарушено.
  • Физическое подключение относится к физическим сетевым каналам — проводам, беспроводным сигналам, маршрутизаторам и т. д., которые упрощают обмен данными между клиентским компьютером и серверным компьютером. Физическое подключение должно присутствовать для установления транспортного подключения, и для установления подключения к транспорту необходимо установить транспортное подключение. Однако нарушение физического подключения не всегда немедленно завершает транспортное подключение или подключение SignalR, как описано далее в этом разделе.

На следующей схеме подключение SignalR представлено уровнем API Центров и API PersistentConnection SignalR, транспортное подключение представлено уровнем транспорта, а физическое соединение представлено линиями между сервером и клиентами.

Схема архитектуры SignalR

При вызове Start метода в клиенте SignalR вы предоставляете код клиента SignalR со всеми сведениями, необходимыми для установления физического подключения к серверу. Код клиента SignalR использует эти сведения для выполнения HTTP-запроса и установления физического подключения, использующего один из четырех методов транспорта. Если подключение к транспорту завершается сбоем или сервер завершается ошибкой, подключение SignalR не уйдет немедленно, так как клиент по-прежнему имеет сведения, необходимые для автоматического повторного установления нового транспортного подключения к тому же URL-адресу SignalR. В этом сценарии никакого вмешательства от пользовательского приложения не участвует, и когда клиентский код SignalR устанавливает новое транспортное подключение, он не запускает новое подключение SignalR. Непрерывность подключения SignalR отражается на том, что идентификатор подключения, созданный при вызове Start метода, не изменяется.

Обработчик OnReconnected событий в Концентраторе выполняется при автоматическом повторном установке транспортного подключения после потери. Обработчик OnDisconnected событий выполняется в конце подключения SignalR. Подключение SignalR может завершиться любым из следующих способов:

  • Если клиент вызывает Stop метод, то на сервер отправляется сообщение остановки, а подключение SignalR немедленно завершается как клиентом, так и сервером.
  • После потери подключения между клиентом и сервером клиент пытается повторно подключиться, а сервер ожидает повторного подключения клиента. Если попытки повторного подключения завершаются неудачно, а период ожидания отключения заканчивается, клиент и сервер заканчиваются подключением SignalR. Клиент перестает пытаться повторно подключиться, и сервер удаляет его представление подключения SignalR.
  • Если клиент перестает работать без возможности вызова Stop метода, сервер ожидает повторного подключения клиента, а затем завершает подключение SignalR после периода ожидания отключения.
  • Если сервер перестает работать, клиент пытается повторно подключиться (повторно создать транспортное подключение), а затем завершает подключение SignalR после периода ожидания отключения.

Если нет проблем с подключением, а пользовательское приложение завершает подключение SignalR путем вызова Stop метода, соединение SignalR и транспортное подключение начинаются и заканчиваются примерно одновременно. В следующих разделах подробно описаны другие сценарии.

Сценарии отключения транспорта

Физические подключения могут быть медленными или могут возникнуть прерывания подключения. В зависимости от таких факторов, как продолжительность прерывания, подключение к транспорту может быть удалено. Затем SignalR пытается повторно установить транспортное подключение. Иногда API подключения транспорта обнаруживает прерывание и удаляет транспортное подключение, и SignalR сразу же обнаруживает, что соединение потеряно. В других сценариях ни API подключения к транспорту, ни SignalR не сразу же осознают, что подключение было потеряно. Для всех транспортных средств, кроме длительного опроса, клиент SignalR использует функцию с именем keepalive для проверки потери подключения, что API транспорта не может обнаружить. Сведения о длинных подключениях опроса см. в разделе "Время ожидания" и "Сохранение параметров" далее в этом разделе.

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

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

  • Транспорт — WebSockets, навсегда кадр или события, отправленные сервером.
  • В физическом сетевом подключении возникают различные периоды прерывания.
  • API транспорта не узнает о прерываниях, поэтому SignalR полагается на функциональность хранения для их обнаружения.

Отключение транспорта

Если клиент переходит в режим повторного подключения, но не может установить транспортное подключение в пределах ограничения времени ожидания отключения, сервер завершает подключение SignalR. В этом случае сервер выполняет метод центра OnDisconnected и помещает в очередь сообщение об отключении для отправки клиенту в случае, если клиент управляет подключением позже. Если клиент повторно подключается, он получает команду отключения и вызывает Stop метод. В этом сценарии OnReconnected не выполняется при повторном подключении клиента и OnDisconnected не выполняется при вызове Stopклиента. На следующей схеме показан этот сценарий.

Прерывания транспорта — время ожидания сервера

События времени существования подключения SignalR, которые могут быть вызваны на клиенте, являются следующими:

  • ConnectionSlow событие клиента.

    Возникает, когда предустановленная доля периода ожидания хранения прошла с момента получения последнего сообщения или проверки пинга. Период предупреждения времени ожидания по умолчанию — 2/3 времени ожидания. Время ожидания хранения составляет 20 секунд, поэтому предупреждение возникает около 13 секунд.

    По умолчанию сервер отправляет контрольные связи каждые 10 секунд, а клиент проверяет наличие пингов каждые 2 секунды (одна треть разницы между значением тайм-аута и значением предупреждения тайм-аута).

    Если API транспорта становится известно об отключении, SignalR может быть проинформирован об отключении до прохождения периода предупреждения времени ожидания. В этом случае ConnectionSlow событие не будет возникать, и SignalR перейдет непосредственно к событию Reconnecting .

  • Reconnecting событие клиента.

    Возникает, когда (a) API транспорта обнаруживает, что соединение потеряно, или (b) период времени ожидания хранения прошел с момента получения последнего сообщения или проверки связи. Клиентский код SignalR начинает пытаться повторно подключиться. Это событие можно обрабатывать, если приложение будет принимать некоторые действия при потере транспортного подключения. Период времени ожидания по умолчанию составляет 20 секунд.

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

  • Reconnected событие клиента.

    Вызывается при повторном подключении к транспорту. Обработчик OnReconnected событий в Концентраторе выполняется.

  • Closed событие клиента (disconnected событие в JavaScript).

    Возникает, когда истекает период ожидания отключения, пока код клиента SignalR пытается повторно подключиться после потери транспортного подключения. Время ожидания отключения по умолчанию — 30 секунд. (Это событие также возникает при завершении подключения, так как Stop вызывается метод.)

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

Некоторые сетевые среды намеренно закрывают неактивные подключения, а другая функция хранимых пакетов — помочь предотвратить это, предоставив этим сетям знать, что подключение SignalR используется. В крайних случаях частота проверки связи по умолчанию может оказаться недостаточной, чтобы предотвратить закрытые подключения. В этом случае можно настроить отправку пингов с сохранением чаще. Дополнительные сведения см. в разделе "Время ожидания" и "Сохранение параметров " далее в этом разделе.

Примечание.

Важно: последовательность событий, описанных здесь, не гарантируется. SignalR делает каждую попытку вызвать события времени существования подключения предсказуемым образом в соответствии с этой схемой, но существует множество вариантов сетевых событий и многих способов, в которых базовые платформы коммуникации, такие как API транспорта, обрабатывают их. Например, Reconnected событие может не вызываться при повторном подключении клиента или OnConnected обработчик на сервере может выполняться при неудачной попытке установить подключение. В этом разделе описываются только эффекты, которые обычно создаются определенными типичными обстоятельствами.

Сценарии отключения клиента

В клиенте браузера код клиента SignalR, который поддерживает подключение SignalR, выполняется в контексте JavaScript веб-страницы. Вот почему подключение SignalR должен завершиться при переходе с одной страницы на другую, и именно поэтому при подключении из нескольких окон браузера или вкладок у вас есть несколько подключений с несколькими идентификаторами подключений. Когда пользователь закрывает окно браузера или вкладку, переходит на новую страницу или обновляет страницу, подключение SignalR немедленно заканчивается, так как клиентский код SignalR обрабатывает это событие браузера и вызывает Stop метод. В этих сценариях или на любой клиентской платформе, когда приложение вызывает Stop метод, OnDisconnected обработчик событий выполняется немедленно на сервере, а клиент вызывает Closed событие (событие называется disconnected в JavaScript).

Если клиентское приложение или компьютер, на котором он работает при сбоях или переходит в спящий режим (например, когда пользователь закрывает ноутбук), сервер не сообщает о том, что произошло. Насколько известно серверу, потеря клиента может быть вызвана прерыванием подключения, и клиент может попытаться повторно подключиться. Поэтому в этих сценариях сервер ожидает повторного подключения клиента и OnDisconnected не выполняется до истечения срока ожидания отключения (около 30 секунд по умолчанию). На следующей схеме показан этот сценарий.

Сбой клиентского компьютера

Сценарии отключения сервера

Когда сервер переходит в автономный режим, он перезагружается, завершается сбоем, домен приложения и т. д. Результат может быть похож на потерянное соединение, или api транспорта и SignalR могут сразу же знать, что сервер исчез, и SignalR может начать повторное подключение без вызова ConnectionSlow события. Если клиент переходит в режим повторного подключения, и если сервер восстанавливается или перезапускается, или новый сервер подключен к сети до истечения срока ожидания отключения, клиент будет повторно подключаться к восстановленным или новому серверу. В этом случае подключение SignalR продолжается на клиенте и Reconnected вызывается событие. На первом сервере OnDisconnected никогда не выполняется и на новом сервере OnReconnected выполняется, хотя OnConnected он никогда не выполнялся для этого клиента на этом сервере раньше. (Результат такой же, если клиент повторно подключается к тому же серверу после перезагрузки или перезапуска домена приложения, так как при перезапуске сервера нет памяти о предыдущем действии подключения.) На следующей схеме предполагается, что API транспорта сразу же узнает о потерянной связи, поэтому ConnectionSlow событие не вызывается.

Сбой сервера и повторное подключение Если сервер не станет доступным в течение периода ожидания отключения, подключение SignalR завершается. В этом сценарии событие "Закрыто" ("отключено" в клиентах JavaScript) вызывается на клиенте, но onDisconnected никогда не вызывается на сервере. На следующей схеме предполагается, что API транспорта не узнает о потерянном соединении, поэтому он обнаруживается функцией поддержания SignalR и вызывается событие ConnectionSlow.

Сбой сервера и время ожидания

Параметры времени ожидания и сохранения

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

ConnectionTimeout

Этот параметр представляет время, которое нужно оставить транспортное подключение открытым и ожидая ответа, прежде чем закрыть его и открыть новое подключение. Значение по умолчанию — 110 секунд.

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

Длинное подключение к транспорту опроса

DisconnectTimeout

Этот параметр представляет время ожидания после потери транспортного подключения перед вызовом Disconnected события. Значение по умолчанию — 30 секунд. При установке DisconnectTimeoutKeepAlive автоматически устанавливается значение 1/3 DisconnectTimeout значения.

KeepAlive

Этот параметр представляет время ожидания перед отправкой сохраняемого пакета через неактивное подключение. Значение по умолчанию — 10 секунд. Это значение не должно превышать 1/3 DisconnectTimeout значения.

Если вы хотите задать оба DisconnectTimeout и KeepAlive, задайте KeepAlive после DisconnectTimeout. В противном случае параметр KeepAlive будет перезаписан, если DisconnectTimeout автоматически устанавливается KeepAlive значение 1/3 значения времени ожидания.

Если вы хотите отключить функцию сохранения, установите KeepAlive значение NULL. Функциональность хранения автоматически отключается для длительного транспорта опроса.

Изменение времени ожидания и сохранения параметров

Чтобы изменить значения по умолчанию для этих параметров, задайте их в Application_Start файле Global.asax , как показано в следующем примере. Значения, отображаемые в примере кода, совпадают со значениями по умолчанию.

protected void Application_Start(object sender, EventArgs e)
{
    // Make long polling connections wait a maximum of 110 seconds for a
    // response. When that time expires, trigger a timeout command and
    // make the client reconnect.
    GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(110);
    
    // Wait a maximum of 30 seconds after a transport connection is lost
    // before raising the Disconnected event to terminate the SignalR connection.
    GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(30);
    
    // For transports other than long polling, send a keepalive packet every
    // 10 seconds. 
    // This value must be no more than 1/3 of the DisconnectTimeout value.
    GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(10);
    
    RouteTable.Routes.MapHubs();
}

Как уведомить пользователя об отключении

В некоторых приложениях может потребоваться отобразить сообщение пользователю при возникновении проблем с подключением. У вас есть несколько вариантов того, как и когда это сделать. Ниже приведены примеры кода для клиента JavaScript с помощью созданного прокси-сервера.

  • Обработайте connectionSlow событие, чтобы отобразить сообщение, как только SignalR знает о проблемах подключения, прежде чем он переходит в режим повторного подключения.

    $.connection.hub.connectionSlow(function() {
        notifyUserOfConnectionProblem(); // Your function to notify user.
    });
    
  • Обработайте reconnecting событие для отображения сообщения, когда SignalR знает об отключении и переходит в режим повторного подключения.

    $.connection.hub.reconnecting(function() {
        notifyUserOfTryingToReconnect(); // Your function to notify user.
    });
    
  • Обработайте disconnected событие, чтобы отобразить сообщение при попытке повторного подключения истекло время ожидания. В этом сценарии единственным способом повторного установления соединения с сервером является перезапуск подключения SignalR путем вызова Start метода, который создаст новый идентификатор подключения. В следующем примере кода используется флаг, чтобы убедиться, что вы выдаете уведомление только после повторного ожидания подключения, а не после обычного окончания подключения SignalR, вызванного вызовом Stop метода.

    var tryingToReconnect = false;
    
    $.connection.hub.reconnecting(function() {
        tryingToReconnect = true;
    });
    
    $.connection.hub.reconnected(function() {
        tryingToReconnect = false;
    });
    
    $.connection.hub.disconnected(function() {
        if(tryingToReconnect) {
            notifyUserOfDisconnect(); // Your function to notify user.
        }
    });
    

Непрерывное повторное подключение

В некоторых приложениях может потребоваться автоматически повторно установить подключение после его потери и время ожидания повторного подключения. Для этого можно вызвать Start метод из Closed обработчика событий (disconnected обработчик событий на клиентах JavaScript). Может потребоваться подождать некоторое время перед вызовом Start , чтобы избежать этого слишком часто, когда сервер или физическое подключение недоступны. Следующий пример кода предназначен для клиента JavaScript с помощью созданного прокси-сервера.

$.connection.hub.disconnected(function() {
   setTimeout(function() {
       $.connection.hub.start();
   }, 5000); // Restart connection after 5 seconds.
});

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

Отключение клиента в коде сервера

У SignalR версии 2 нет встроенного API сервера для отключения клиентов. В будущем есть планы по добавлению этой функции. В текущем выпуске SignalR самый простой способ отключить клиент от сервера — реализовать метод отключения на клиенте и вызвать этот метод с сервера. В следующем примере кода показан метод отключения для клиента JavaScript с помощью созданного прокси-сервера.

var myHubProxy = $.connection.myHub
myHubProxy.client.stopClient = function() {
    $.connection.hub.stop();
};

Предупреждение

Безопасность. Ни этот метод для отключения клиентов, ни предлагаемый встроенный API не будет решать сценарий взломанных клиентов, выполняющих вредоносный код, так как клиенты могут повторно подключиться или взломанный код может удалить stopClient метод или изменить то, что он делает. Соответствующее место для реализации защиты типа "отказ в обслуживании" (DOS) не находится на платформе или на уровне сервера, а в интерфейсной инфраструктуре.

Обнаружение причины отключения

SignalR 2.1 добавляет перегрузку к событию сервера OnDisconnect , указывающее, намеренно ли клиент отключен, а не время ожидания. Параметр имеет значение true, StopCalled если клиент явно закрыл подключение. В JavaScript, если ошибка сервера привела клиента к отключению, сведения об ошибке будут переданы клиенту как $.connection.hub.lastError.

Код сервера C#: stopCalled параметр

public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
    if (stopCalled)
    {
        Console.WriteLine(String.Format("Client {0} explicitly closed the connection.", Context.ConnectionId));
    }
    else
    {
        Console.WriteLine(String.Format("Client {0} timed out .", Context.ConnectionId));
    }
            
    return base.OnDisconnected(stopCalled);
}

Клиентский код JavaScript: доступ lastError к событию disconnect .

$.connection.hub.disconnected(function () {
    if ($.connection.hub.lastError) 
        { alert("Disconnected. Reason: " +  $.connection.hub.lastError.message); }
});