Общие сведения и обработка событий времени существования подключения в SignalR 1.x
Патрик Флетчер (Patrick Fletcher),Том Дайкстра (Tom Dykstra)
Предупреждение
Эта документация не подходит для последней версии SignalR. Ознакомьтесь с ASP.NET Core SignalR.
В этой статье представлен обзор событий подключения, повторного подключения и отключения SignalR, которые можно обрабатывать, а также параметров времени ожидания и сохранения, которые можно настроить.
В этой статье предполагается, что у вас уже есть некоторые знания о Событиях SignalR и времени существования подключения. Общие сведения о SignalR см. в разделе SignalR — обзор — начало работы. Список событий времени существования подключения см. в следующих ресурсах:
Общие сведения
В этом разделе содержатся следующие подразделы:
Ссылки на справочные статьи по API относятся к версии API для .NET 4.5. Если вы используете .NET 4, ознакомьтесь с разделами api версии .NET 4.
Терминология и сценарии времени существования подключения
Обработчик OnReconnected
событий в концентраторе SignalR может выполняться непосредственно после OnConnected
, но не после OnDisconnected
для данного клиента. Причина, по которой можно выполнить повторное подключение без отключения, заключается в том, что в SignalR используется слово "соединение".
Подключения SignalR, транспортные подключения и физические подключения
В этой статье рассматриваются подключения SignalR, подключения транспорта и физические подключения:
- Подключение SignalR — это логическая связь между клиентом и URL-адресом сервера, поддерживаемая API SignalR и однозначно определяемая идентификатором подключения. Данные об этой связи поддерживаются SignalR и используются для установления транспортного соединения. Связь заканчивается, и SignalR удаляет данные, когда клиент вызывает
Stop
метод или достигается ограничение времени ожидания, пока SignalR пытается восстановить потерянное транспортное подключение. - Транспортное подключение — это логическая связь между клиентом и сервером, поддерживаемая одним из четырех ТРАНСПОРТНЫХ API: WebSockets, события, отправленные сервером, навсегда кадр или длинный опрос. SignalR использует ТРАНСПОРТНЫЙ API для создания транспортного подключения, а API транспорта зависит от наличия физического сетевого подключения для создания транспортного подключения. Транспортное подключение завершается, когда SignalR завершает его или когда API транспорта обнаруживает, что физическое соединение нарушено.
- Физическое подключение относится к физическим сетевым каналам — проводам, беспроводным сигналам, маршрутизаторам и т. д. — упрощают обмен данными между клиентским компьютером и серверным компьютером. Чтобы установить транспортное соединение, должно быть установлено физическое соединение, а для установления соединения SignalR должно быть установлено транспортное соединение. Однако нарушение физического подключения не всегда немедленно завершает транспортное подключение или подключение SignalR, как будет описано далее в этом разделе.
На следующей схеме подключение SignalR представлено уровнями Api Концентраторов и Api PersistentConnection 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 транспорта не может обнаружить. Сведения о длительных опросах подключений см. в разделе Timeout and keepalive settings далее в этом разделе.
Если подключение неактивно, сервер периодически отправляет клиенту пакет keepalive. На дату написания этой статьи частота по умолчанию — каждые 10 секунд. Прослушивая эти пакеты, клиенты могут определить, возникла ли проблема с подключением. Если пакет keepalive не получен, когда ожидалось, через некоторое время клиент предполагает наличие проблем с подключением, таких как медленная работа или прерывание работы. Если keepalive по-прежнему не получен через более длительное время, клиент предполагает, что подключение было разорвано, и начинает попытки повторного подключения.
На следующей схеме показаны события клиента и сервера, которые возникают в типичном сценарии, когда возникают проблемы с физическим подключением, которые не распознаются API транспорта сразу. Схема применяется к следующим обстоятельствам:
- Транспортом является WebSockets, forever frame или события, отправленные сервером.
- Существуют различные периоды прерывания физического сетевого подключения.
- API транспорта не получает сведения о прерываниях, поэтому SignalR использует функциональность keepalive для их обнаружения.
Если клиент переходит в режим повторного подключения, но не может установить транспортное подключение в течение времени ожидания отключения, сервер завершает подключение SignalR. В этом случае сервер выполняет метод концентратора OnDisconnected
и помещает в очередь сообщение об отключении для отправки клиенту на случай, если клиенту удастся подключиться позже. Если клиент выполняет повторное подключение, он получает команду отключения и вызывает Stop
метод . В этом сценарии не выполняется при OnReconnected
повторном подключении клиента и OnDisconnected
не выполняется при вызове Stop
клиентом . Этот сценарий показан на следующей схеме.
На клиенте могут возникать следующие события времени существования подключения SignalR:
ConnectionSlow
событие клиента.Возникает, когда с момента получения последнего сообщения или проверки активности истекла предустановленная доля времени ожидания. Период предупреждения об истечении времени ожидания по умолчанию составляет 2/3 от времени ожидания keepalive. Время ожидания keepalive составляет 20 секунд, поэтому предупреждение возникает примерно через 13 секунд.
По умолчанию сервер отправляет проверки связи по проверке проверки связи каждые 10 секунд, а клиент проверяет наличие проверки проверки связи примерно каждые 2 секунды (одна треть разницы между значением времени ожидания keepalive и значением предупреждения об истечении времени ожидания).
Если API транспорта узнает об отключении, SignalR может быть проинформирован об отключении до истечения периода предупреждения о тайм-ауте keepalive. В этом случае
ConnectionSlow
событие не будет вызываться, и SignalR перейдет непосредственно к событиюReconnecting
.Reconnecting
событие клиента.Возникает, когда (а) API транспорта обнаруживает, что подключение потеряно, или (б) время ожидания проверки активности прошло с момента получения последнего сообщения или проверки связи с сохранением. Код клиента SignalR начинает пытаться повторно подключиться. Это событие можно обработать, если требуется, чтобы приложение пустилось в какое-либо действие при потере транспортного подключения. Время ожидания по умолчанию составляет 20 секунд.
Если клиентский код пытается вызвать метод концентратора, когда SignalR находится в режиме повторного подключения, SignalR попытается отправить команду. В большинстве случаев такие попытки завершаются неудачей, но в некоторых случаях они могут быть успешными. Для событий, отправляемых сервером, транспорта с бессрочной рамкой и длительным опросом, SignalR использует два канала связи, один из них используется клиентом для отправки сообщений, а другой — для получения сообщений. Для получения используется постоянно открытый канал, который закрывается при прерывании физического подключения. Канал, используемый для отправки, остается доступным, поэтому при восстановлении физического подключения вызов метода от клиента к серверу может быть успешным до повторного создания канала получения. Возвращаемое значение не будет получено, пока SignalR повторно не откроет канал, используемый для получения.
Reconnected
событие клиента.Возникает при восстановлении транспортного подключения. Выполняется
OnReconnected
обработчик событий в концентраторе.Closed
client event (disconnected
событие в JavaScript).Возникает, когда истекает время ожидания отключения, когда код клиента SignalR пытается повторно подключиться после потери транспортного подключения. Время ожидания отключения по умолчанию составляет 30 секунд. (Это событие также возникает при завершении подключения, так как
Stop
вызывается метод.)
Прерывания подключения транспорта, которые не обнаруживаются API транспорта и не задерживают получение проверки связи с сервером дольше, чем период предупреждения об истечении времени ожидания, может не вызывать никаких событий времени существования подключения.
Некоторые сетевые среды намеренно закрывают неактивные подключения, а другая функция пакетов keepalive — помочь предотвратить это, сообщая этим сетям, что используется подключение SignalR. В крайних случаях частоты проверки связи по умолчанию может быть недостаточно для предотвращения закрытых подключений. В этом случае вы можете настроить ping keepalive для более частой отправки. Дополнительные сведения см. в разделе Timeout and keepalive settings далее в этой статье.
Примечание
Важно!
Последовательность событий, описанная здесь, не гарантируется. 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 завершается. В этом сценарии событие (disconnected
в клиентах JavaScript) вызывается на клиенте, Closed
но OnDisconnected
никогда не вызывается на сервере. На следующей схеме предполагается, что API транспорта не получает сведения о потерянном подключении, поэтому оно обнаруживается функцией поддержки SignalR и ConnectionSlow
вызывается событие.
Время ожидания и параметры сохранения
Значения по умолчанию ConnectionTimeout
, DisconnectTimeout
и KeepAlive
подходят для большинства сценариев, но их можно изменить, если ваша среда имеет особые потребности. Например, если сетевая среда закрывает соединения, которые простаивают в течение 5 секунд, может потребоваться уменьшить значение keepalive.
ConnectionTimeout
Этот параметр представляет время, в течение которого транспортное подключение остается открытым и ожидает ответа, прежде чем закрыть его и открыть новое подключение. Значение по умолчанию — 110 секунд.
Этот параметр применяется только в том случае, если функциональность keepalive отключена, что обычно применяется только к долгому транспорту опроса. На следующей схеме показано влияние этого параметра на длинное транспортное подключение опроса.
DisconnectTimeout
Этот параметр представляет время ожидания после потери транспортного подключения до вызова Disconnected
события. Значение по умолчанию — 30 секунд. При установке DisconnectTimeout
KeepAlive
автоматически устанавливается значение 1/3 значенияDisconnectTimeout
.
KeepAlive
Этот параметр представляет время ожидания перед отправкой пакета keepalive через неактивное подключение. Значение по умолчанию — 10 секунд. Это значение не должно превышать 1/3 значения DisconnectTimeout
.
Если вы хотите задать и DisconnectTimeout
KeepAlive
, задайте после KeepAlive
DisconnectTimeout
. В противном случае параметр KeepAlive
будет перезаписан, если DisconnectTimeout
автоматически устанавливается KeepAlive
значение 1/3 от значения времени ожидания.
Если вы хотите отключить функциональность keepalive, задайте значение KeepAlive
NULL. Функция Keepalive автоматически отключается для транспорта длительного опроса.
Изменение параметров времени ожидания и сохранения
Чтобы изменить значения по умолчанию для этих параметров, задайте их в 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);
}
Как уведомить пользователя об отключении
В некоторых приложениях может потребоваться отобразить сообщение для пользователя при возникновении проблем с подключением. У вас есть несколько вариантов того, как и когда это сделать. Приведенные ниже примеры кода предназначены для клиента 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. } });
Непрерывное повторное подключение
В некоторых приложениях может потребоваться автоматически восстановить подключение после его потери и превышения времени ожидания попытки повторного подключения. Для этого можно вызвать метод из Closed
обработчика Start
событий (disconnected
обработчик событий на клиентах JavaScript). Вы можете подождать некоторое время перед вызовом Start
, чтобы избежать этого слишком часто, когда сервер или физическое подключение недоступны. Следующий пример кода предназначен для клиента JavaScript, использующий созданный прокси-сервер.
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
Потенциальная проблема, которую следует учитывать в мобильных клиентах, заключается в том, что непрерывные попытки повторного подключения, когда сервер или физическое подключение недоступны, могут привести к ненужению заряда батареи.
Отключение клиента в коде сервера
SignalR версии 1.1.1 не имеет встроенного API сервера для отключения клиентов. Есть планы по добавлению этой функции в будущем. В текущем выпуске SignalR самый простой способ отключить клиент от сервера — реализовать метод отключения на клиенте и вызвать этот метод с сервера. В следующем примере кода показан метод отключения для клиента JavaScript с помощью созданного прокси-сервера.
var myHubProxy = $.connection.myHub
myHubProxy.client.stopClient = function() {
$.connection.hub.stop();
};
Предупреждение
Безопасность. Ни этот метод отключения клиентов, ни предлагаемый встроенный API не будут учитывать сценарий взломанных клиентов, выполняющих вредоносный код, так как клиенты могут повторно подключиться, а взломанные коды могут удалить stopClient
метод или изменить его действия. Подходящее место для реализации защиты от отказа в обслуживании (DOS) с отслеживанием состояния находится не на уровне платформы или сервера, а в интерфейсной инфраструктуре.