Principy a zpracování událostí doby platnosti v knihovně SignalR
Upozornění
Tato dokumentace není určená pro nejnovější verzi SignalR. Podívejte se na ASP.NET Core SignalR.
Tento článek obsahuje přehled událostí připojení, opětovného připojení a odpojení služby SignalR, které můžete zpracovat, a nastavení časového limitu a udržování, které můžete nakonfigurovat.
Článek předpokládá, že už máte určité znalosti o signalR a událostech životnosti připojení. Úvod ke službě SignalR najdete v tématu Úvod do Služby SignalR. Seznam událostí životnosti připojení najdete v následujících zdrojích informací:
- Zpracování událostí životnosti připojení ve třídě Hub
- Zpracování událostí životnosti připojení v klientech JavaScriptu
- Zpracování událostí životnosti připojení v klientech .NET
Verze softwaru použité v tomto tématu
- Visual Studio 2017
- .NET 4.5
- SignalR verze 2
Předchozí verze tohoto tématu
Informace o starších verzích služby SignalR najdete v tématu Starší verze služby SignalR.
Dotazy a komentáře
Pošlete nám prosím zpětnou vazbu k tomu, jak se vám tento kurz líbil a co bychom mohli vylepšit v komentářích v dolní části stránky. Pokud máte dotazy, které přímo nesouvisejí s kurzem, můžete je publikovat na fóru ASP.NET SignalR nebo StackOverflow.com.
Přehled
Tento článek obsahuje následující části:
Odkazy na referenční témata rozhraní API jsou na verzi rozhraní API .NET 4.5. Pokud používáte .NET 4, projděte si témata týkající se rozhraní API verze .NET 4.
Terminologie a scénáře doby života připojení
Obslužná rutina OnReconnected
události v centru SignalR hub může pro daného klienta provést přímo po OnConnected
, ale ne po OnDisconnected
ní. Důvodem, proč můžete mít opětovné připojení bez odpojení, je několik způsobů, jak se slovo "připojení" používá v SignalR.
Připojení SignalR, přenosová připojení a fyzická připojení
Tento článek bude rozlišovat mezi připojeními SignalR, dopravními afyzickými připojeními:
- Připojení SignalR odkazuje na logický vztah mezi klientem a adresou URL serveru, který je udržován rozhraním SIGNALR API a jednoznačně identifikovaný ID připojení. Data o této relaci jsou spravována službou SignalR a používají se k vytvoření přenosového připojení. Relace se ukončí a SignalR odstraní data, když klient zavolá metodu
Stop
nebo dojde k dosažení časového limitu, zatímco se SignalR pokouší znovu navázat ztracené přenosové připojení. - Přenosové připojení označuje logický vztah mezi klientem a serverem, který udržuje jedno ze čtyř přenosových rozhraní API: WebSocket, události odeslané serverem, rámec forever nebo dlouhé dotazování. SignalR používá rozhraní API pro přenos k vytvoření přenosového připojení a rozhraní API pro přenos závisí na existenci fyzického síťového připojení. Přenosové připojení se ukončí, když ho signalR ukončí nebo když rozhraní API pro přenos zjistí, že fyzické připojení je přerušené.
- Fyzické připojení označuje fyzická síťová propojení – vodiče, bezdrátové signály, směrovače atd. - usnadňují komunikaci mezi klientským počítačem a serverovým počítačem. Fyzické připojení musí být přítomno, aby bylo možné vytvořit dopravní spojení, a aby bylo možné navázat připojení SignalR, musí být vytvořeno dopravní spojení. Přerušení fyzického připojení však ne vždy okamžitě ukončí přenosové připojení nebo připojení SignalR, jak bude vysvětleno dále v tomto tématu.
V následujícím diagramu je připojení SignalR reprezentováno rozhraním Hubs API a vrstvou SignalR rozhraní API PersistentConnection, přenosové připojení je reprezentováno vrstvou Transports a fyzické připojení je reprezentováno spojnicemi mezi serverem a klienty.
Při volání Start
metody v klientovi SignalR poskytujete kód klienta SignalR se všemi informacemi, které potřebuje k navázání fyzického připojení k serveru. Kód klienta SignalR používá tyto informace k vytvoření požadavku HTTP a navázání fyzického připojení, které používá jednu ze čtyř metod přenosu. Pokud se přenosové připojení nezdaří nebo server selže, připojení SignalR neodejde okamžitě, protože klient stále má informace potřebné k automatickému opětovnému navázání nového přenosového připojení na stejnou adresu URL signalR. V tomto scénáři není zahrnut žádný zásah z uživatelské aplikace a když kód klienta SignalR naváže nové přenosové připojení, nezačne nové připojení SignalR. Kontinuita připojení SignalR se odráží ve skutečnosti, že ID připojení, které se vytvoří při volání Start
metody, se nezmění.
Obslužná rutina OnReconnected
události v centru se spustí, když se po ztrátě automaticky znovu vytvoří přenosové připojení. Obslužná rutina OnDisconnected
události se spustí na konci připojení SignalR. Připojení SignalR může skončit některým z následujících způsobů:
- Pokud klient zavolá metodu
Stop
, odešle se na server zpráva o zastavení a klient i server okamžitě ukončí připojení SignalR. - Po ztrátě připojení mezi klientem a serverem se klient pokusí znovu připojit a server čeká, až se klient znovu připojí. Pokud jsou pokusy o opětovné připojení neúspěšné a časový limit odpojení skončí, klient i server ukončí připojení SignalR. Klient se přestane pokoušet o opětovné připojení a server odstraní svou reprezentaci připojení SignalR.
- Pokud klient přestane běžet bez možnosti volat metodu
Stop
, server počká, až se klient znovu připojí, a poté ukončí připojení SignalR po uplynutí časového limitu odpojení. - Pokud server přestane běžet, klient se pokusí znovu připojit (znovu vytvořit přenosové připojení) a po uplynutí časového limitu odpojení ukončí připojení SignalR.
Pokud nedojde k žádným problémům s připojením a uživatelská aplikace ukončí připojení SignalR voláním Stop
metody, připojení SignalR a přenosové připojení začínají a končí přibližně ve stejnou dobu. Další scénáře jsou podrobněji popsány v následujících částech.
Scénáře odpojení přenosu
Fyzická připojení můžou být pomalá nebo může docházet k přerušení připojení. V závislosti na faktorech, jako je délka přerušení, může být přepravní spojení ukončeno. SignalR se pak pokusí znovu navázat přenosové připojení. Někdy rozhraní API přenosového připojení zjistí přerušení a přeruší přenosové připojení a SignalR okamžitě zjistí, že připojení bylo ztraceno. V jiných scénářích rozhraní API pro přenos ani SignalR okamžitě neznají, že došlo ke ztrátě připojení. Pro všechny přenosy s výjimkou dlouhého dotazování klient SignalR používá funkci s názvem keepalive ke kontrole ztráty připojení, kterou rozhraní API pro přenos nedokáže rozpoznat. Informace o dlouhých dotazovacích připojeních najdete v části Nastavení vypršení časového limitu a uchování dál v tomto tématu.
Pokud je připojení neaktivní, server pravidelně odesílá klientovi paket keepalive. K datu psaní tohoto článku je výchozí frekvence každých 10 sekund. Nasloucháním těchto paketů můžou klienti zjistit, jestli nedošlo k problému s připojením. Pokud se paket keepalive nepřinese podle očekávání, klient po krátké době předpokládá, že dochází k problémům s připojením, jako je zpomalení nebo přerušení. Pokud se příkaz keepalive ani po delší době neobdrží, klient předpokládá, že připojení bylo ukončeno, a začne se pokoušet o opětovné připojení.
Následující diagram znázorňuje události klienta a serveru, které jsou vyvolány v typickém scénáři, když dojde k problémům s fyzickým připojením, které rozhraní API pro přenos okamžitě nerozpozná. Diagram se vztahuje na následující okolnosti:
- Přenos je WebSocket, forever frame nebo události odeslané serverem.
- Fyzické síťové připojení má různá období přerušení.
- Rozhraní API pro přenos si o přerušeních neuvědomuje, takže SignalR spoléhá při jejich detekci na funkci keepalive.
Pokud klient přejde do režimu opětovného připojení, ale nemůže navázat přenosové připojení v rámci časového limitu odpojení, server ukončí připojení SignalR. Když k tomu dojde, server spustí metodu centra OnDisconnected
a zařadí zprávu o odpojení, která se odešle klientovi pro případ, že se klient později připojí. Pokud se klient znovu připojí, přijme příkaz pro odpojení a zavolá metodu Stop
. V tomto scénáři OnReconnected
se nespustí, když se klient znovu připojí, a OnDisconnected
nespustí se, když klient zavolá Stop
. Následující diagram znázorňuje tento scénář.
Události životnosti připojení SignalR, které mohou být vyvolány na klientovi, jsou následující:
ConnectionSlow
událost klienta.Vyvolá se v případě, že od poslední zprávy nebo přijetí příkazu ping pro uchování uplynula přednastavená část časového limitu keepalive. Výchozí období upozornění na časový limit keepalive je 2/3 časového limitu keepalive. Časový limit keepalive je 20 sekund, takže k upozornění dochází přibližně po 13 sekundách.
Ve výchozím nastavení server odesílá příkazy ping typu keepalive každých 10 sekund a klient kontroluje příkazy ping typu keepalive přibližně každé 2 sekundy (jedna třetina rozdílu mezi hodnotou časového limitu keepalive a hodnotou upozornění časového limitu keepalive).
Pokud se rozhraní API pro přenos dozví o odpojení, signalR může být o odpojení informován před uplynutím období upozornění na časový limit keepalive. V takovém případě
ConnectionSlow
by událost nebyla vyvolána a SignalR by přešla přímo naReconnecting
událost.Reconnecting
událost klienta.Vyvolána, když (a) rozhraní API pro přenos zjistí, že došlo ke ztrátě připojení, nebo (b) od přijetí poslední zprávy nebo příkazu ping pro uchování uplynul časový limit keepalive. Kód klienta SignalR se začne pokoušet znovu připojit. Tuto událost můžete zpracovat, pokud chcete, aby vaše aplikace při ztrátě přenosového připojení určitou akci podnikla. Výchozí časový limit keepalive je aktuálně 20 sekund.
Pokud se kód klienta pokusí volat metodu Centra, když je SignalR v režimu opětovného připojení, signalR se pokusí odeslat příkaz. Tyto pokusy většinou selžou, ale za určitých okolností můžou být úspěšné. V případě událostí odeslaných serverem, nekonečného rámce a dlouhých přenosů dotazování používá SignalR dva komunikační kanály: jeden, který klient používá k odesílání zpráv, a druhý, který používá k příjmu zpráv. Kanál, který se používá pro příjem, je trvale otevřený, a to je kanál, který se při přerušení fyzického připojení zavře. Kanál použitý pro odesílání zůstává dostupný, takže pokud se obnoví fyzické připojení, volání metody z klienta na server může být úspěšné před opětovným navázáním kanálu příjmu. Vrácená hodnota nebude přijata, dokud SignalR znovu neotevře kanál používaný k příjmu.
Reconnected
událost klienta.Vyvolá se při opětovném navázání dopravního spojení. Obslužná rutina
OnReconnected
události v centru se spustí.Closed
událost klienta (disconnected
událost v JavaScriptu).Vyvolána při vypršení časového limitu odpojení, zatímco se kód klienta SignalR pokouší znovu připojit po ztrátě přenosového připojení. Výchozí časový limit odpojení je 30 sekund. (Tato událost je vyvolána také při ukončení připojení,
Stop
protože je volána metoda.)
Přerušení přenosového připojení, která nejsou zjištěna rozhraním API pro přenos a nezpozdí příjem příkazů ping typu keepalive ze serveru o delší dobu, než je období upozornění na vypršení časového limitu keepalive, nemusí způsobit vyvolání událostí životnosti připojení.
Některá síťová prostředí záměrně ukončují nečinná připojení a další funkcí paketů keepalive je pomoct tomu zabránit tím, že těmto sítím dají vědět, že se používá připojení SignalR. V extrémních případech nemusí výchozí frekvence keepalive ping stačit k tomu, aby se zabránilo zavřeným připojením. V takovém případě můžete nakonfigurovat, aby se příkazy ping keepalive odesílaly častěji. Další informace najdete v části Vypršení časového limitu a nastavení udržování dál v tomto tématu.
Poznámka
Důležité: Pořadí zde popsaných událostí není zaručeno. SignalR se podle tohoto schématu snaží vyvolat události životnosti připojení předvídatelným způsobem, ale existuje mnoho variant síťových událostí a mnoho způsobů, jak je základní komunikační architektury, jako jsou rozhraní API pro přenos, zpracovávají. Například událost nemusí být vyvolána, Reconnected
když se klient znovu připojí, nebo OnConnected
obslužná rutina na serveru může být spuštěna, když pokus o navázání připojení není úspěšný. Toto téma popisuje pouze účinky, které by normálně byly způsobeny určitými typickými okolnostmi.
Scénáře odpojení klienta
V klientovi prohlížeče se kód klienta SignalR, který udržuje připojení SignalR, spouští v kontextu JavaScriptu webové stránky. Proto se připojení SignalR musí ukončit, když přejdete z jedné stránky na jinou, a proto máte více připojení s více ID připojení, pokud se připojujete z více oken prohlížeče nebo karet. Když uživatel zavře okno nebo kartu prohlížeče, přejde na novou stránku nebo aktualizuje stránku, připojení SignalR okamžitě skončí, protože kód klienta SignalR zpracovává tuto událost prohlížeče za vás a volá metodu Stop
. V těchto scénářích nebo v jakékoli klientské platformě, když vaše aplikace volá metodu Stop
, OnDisconnected
obslužná rutina události se okamžitě spustí na serveru a klient vyvolá Closed
událost (událost má název disconnected
v JavaScriptu).
Pokud se klientská aplikace nebo počítač, na kterém je spuštěná, zhroutí nebo přejde do režimu spánku (například když uživatel zavře přenosný počítač), server nebude informován o tom, co se stalo. Pokud server ví, může být ztráta klienta způsobená přerušením připojení a klient se může pokoušet o opětovné připojení. Proto v těchto scénářích server čeká, aby se klient mohl znovu připojit, a OnDisconnected
nespustí se, dokud nevyprší časový limit odpojení (ve výchozím nastavení přibližně 30 sekund). Následující diagram znázorňuje tento scénář.
Scénáře odpojení serveru
Když server přejde do offline režimu – restartuje se, selže, doména aplikace se recykluje atd. – Výsledek se může podobat ztrátě připojení nebo rozhraní API pro přenos a SignalR můžou okamžitě vědět, že server je pryč, a služba SignalR se může začít pokoušet o opětovné připojení bez vyvolání ConnectionSlow
události. Pokud klient přejde do režimu opětovného připojení a pokud se server obnoví nebo restartuje nebo se před vypršením časového limitu odpojení přepojí nový server do režimu online, klient se znovu připojí k obnoveným nebo novému serveru. V takovém případě bude připojení SignalR pokračovat na klientovi a vyvolá se Reconnected
událost. Na prvním serveru OnDisconnected
se nikdy nespustí a na novém serveru se spustí, OnReconnected
i když OnConnected
se pro daného klienta na daném serveru předtím nikdy nespustí. (Efekt je stejný, pokud se klient po restartování nebo recyklaci domény aplikace znovu připojí ke stejnému serveru, protože při restartování serveru nemá žádnou paměť na předchozí aktivitu připojení.) Následující diagram předpokládá, že rozhraní API pro přenos se okamžitě dozví o ztraceném připojení, takže ConnectionSlow
se událost nevyvolá.
Pokud server není dostupný během časového limitu odpojení, připojení SignalR se ukončí. V tomto scénáři Closed
je událost (disconnected
v klientech JavaScriptu) vyvolána na klientovi, ale OnDisconnected
na serveru se nikdy nevolá. V následujícím diagramu se předpokládá, že rozhraní API pro přenos se o ztraceném připojení nedozví, takže ho detekuje funkce keepalive služby SignalR a ConnectionSlow
vyvolá událost.
Časový limit a nastavení zachování
Výchozí ConnectionTimeout
hodnoty , DisconnectTimeout
a KeepAlive
jsou vhodné pro většinu scénářů, ale je možné je změnit, pokud má vaše prostředí zvláštní potřeby. Pokud například vaše síťové prostředí ukončí připojení, která jsou nečinná po dobu 5 sekund, budete muset snížit hodnotu keepalive.
Connectiontimeout
Toto nastavení představuje dobu, po kterou má dopravní připojení nechat otevřené a čekat na odpověď před jeho zavřením a otevřením nového připojení. Výchozí hodnota je 110 sekund.
Toto nastavení platí pouze v případě, že je zakázaná funkce keepalive, což se obvykle vztahuje pouze na dlouhý přenos dotazování. Následující diagram znázorňuje účinek tohoto nastavení na dlouhé přenosové spojení dotazování.
DisconnectTimeout
Toto nastavení představuje dobu čekání po ztrátě přenosového připojení před vyvolání Disconnected
události. Výchozí hodnota je 30 sekund. Když nastavíte DisconnectTimeout
, KeepAlive
automaticky se nastaví na 1/3 DisconnectTimeout
hodnoty.
Keepalive
Toto nastavení představuje dobu čekání před odesláním paketu keepalive přes nečinné připojení. Výchozí hodnota je 10 sekund. Tato hodnota nesmí být větší než 1/3 DisconnectTimeout
hodnoty.
Pokud chcete nastavit jak, tak DisconnectTimeout
i KeepAlive
, nastavte KeepAlive
za DisconnectTimeout
. V opačném případě se vaše KeepAlive
nastavení přepíše, když DisconnectTimeout
se automaticky nastaví KeepAlive
na 1/3 hodnoty časového limitu.
Pokud chcete zakázat funkci keepalive, nastavte KeepAlive
na hodnotu null. Funkce keepalive se pro dlouhý přenos dotazování automaticky zakáže.
Jak změnit časový limit a zachovat nastavení
Pokud chcete změnit výchozí hodnoty pro tato nastavení, nastavte je v Application_Start
souboru Global.asax , jak je znázorněno v následujícím příkladu. Hodnoty zobrazené v ukázkovém kódu jsou stejné jako výchozí hodnoty.
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();
}
Jak uživatele upozornit na odpojení
V některých aplikacích můžete chtít uživateli zobrazit zprávu, když dojde k problémům s připojením. Máte několik možností, jak a kdy to udělat. Následující ukázky kódu jsou určené pro javascriptového klienta používajícího vygenerovaný proxy server.
connectionSlow
Zpracování události tak, aby se zobrazila zpráva, jakmile signalR bude vědět o problémech s připojením, před tím, než přejde do režimu opětovného připojení.$.connection.hub.connectionSlow(function() { notifyUserOfConnectionProblem(); // Your function to notify user. });
reconnecting
Zpracování události tak, aby se zobrazila zpráva, když SignalR ví o odpojení a přejde do režimu opětovného připojení.$.connection.hub.reconnecting(function() { notifyUserOfTryingToReconnect(); // Your function to notify user. });
disconnected
Zpracování události tak, aby se zobrazila zpráva, když vypršel časový limit pokusu o opětovné připojení. V tomto scénáři je jediným způsobem, jak znovu navázat připojení se serverem, restartování připojení SignalR volánímStart
metody, která vytvoří nové ID připojení. Následující ukázka kódu používá příznak, který zajistí, že vydáte oznámení pouze po vypršení časového limitu opětovného připojení, ne po normálním ukončení připojení SignalR způsobenémStop
voláním metody.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. } });
Jak se nepřetržitě znovu připojovat
V některých aplikacích můžete chtít automaticky znovu navázat připojení po jeho ztrátě a vypršení časového limitu pokusu o opětovné připojení. K tomu můžete volat metodu Start
z Closed
obslužné rutiny události (disconnected
obslužná rutina události na klientech JavaScriptu). Před voláním Start
můžete nějakou dobu počkat, abyste se tomu vyhnuli příliš často, když server nebo fyzické připojení nejsou k dispozici. Následující ukázka kódu je určená pro javascriptového klienta používajícího vygenerovaný proxy server.
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
Potenciálním problémem, o kterém je potřeba vědět v mobilních klientech, je to, že pokusy o průběžné opětovné připojení, když není k dispozici server nebo fyzické připojení, můžou způsobit zbytečné vybití baterie.
Jak odpojit klienta v kódu serveru
SignalR verze 2 nemá integrované serverové rozhraní API pro odpojení klientů. V budoucnu plánujeme tuto funkci přidat. V aktuální verzi SignalR je nejjednodušší způsob, jak odpojit klienta od serveru, implementovat metodu odpojení na klientovi a volat tuto metodu ze serveru. Následující ukázka kódu ukazuje metodu odpojení pro klienta JavaScriptu pomocí vygenerovaného proxy serveru.
var myHubProxy = $.connection.myHub
myHubProxy.client.stopClient = function() {
$.connection.hub.stop();
};
Upozornění
Zabezpečení – Tato metoda pro odpojení klientů ani navrhované integrované rozhraní API neřeší scénář napadených klientů se škodlivým kódem, protože klienti se mohou znovu připojit nebo napadený kód může metodu stopClient
odebrat nebo změnit to, co dělá. Vhodným místem pro implementaci stavové ochrany proti odepření služby (DOS) není architektura nebo serverová vrstva, ale spíše front-endová infrastruktura.
Zjištění důvodu odpojení
SignalR 2.1 přidá do události serveru OnDisconnect
přetížení, které indikuje, jestli se klient záměrně odpojil místo vypršení časového limitu. Parametr StopCalled
je true, pokud klient explicitně ukončil připojení. Pokud v JavaScriptu došlo k chybě serveru, která způsobila odpojení klienta, informace o chybě se předají klientovi jako $.connection.hub.lastError
.
Kód serveru C#: stopCalled
parametr
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);
}
Kód klienta JavaScriptu: přístup lastError
k disconnect
události.
$.connection.hub.disconnected(function () {
if ($.connection.hub.lastError)
{ alert("Disconnected. Reason: " + $.connection.hub.lastError.message); }
});
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro