Principy a zpracování událostí doby platnosti v knihovně SignalR
Upozorňující
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í SignalR, které můžete zpracovat a časového limitu a zachovat nastavení, která můžete nakonfigurovat.
V článku se předpokládá, že už máte určité znalosti o událostech životnosti signalR a připojení. Úvod do služby 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ě centra
- Zpracování událostí životnosti připojení v klientech JavaScriptu
- Zpracování událostí životnosti připojení v klientech .NET
Verze softwaru používané 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 naleznete v tématu Starší verze signalR.
Dotazy a komentáře
Napište nám prosím svůj názor na to, 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 nesouvisí 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 k rozhraní API jsou verze rozhraní API .NET 4.5. Pokud používáte .NET 4, podívejte se na témata týkající se rozhraní API verze .NET 4.
Terminologie a scénáře životnosti připojení
Obslužná rutina OnReconnected
události ve službě SignalR Hub se může spustit přímo po OnConnected
daném klientovi, ale ne po OnDisconnected
ní. Důvodem, proč můžete znovu připojit bez odpojení, je, že existuje několik způsobů, jak se ve službě SignalR používá slovo "připojení".
Připojení SignalR, přenosová připojení a fyzická připojení
Tento článek bude rozlišovat mezi připojeními SignalR, přenosovými připojeními a fyzickými připojeními:
- Připojení SignalR odkazuje na logický vztah mezi klientem a adresou URL serveru, který udržuje rozhraní API služby SignalR a jednoznačně identifikované ID připojení. Data o tomto vztahu jsou udržována službou SignalR a slouží k navázání přenosového připojení. Relace končí a SignalR odstraní data, když klient volá metodu
Stop
nebo časový limit, když se SignalR pokouší znovu vytvořit ztracené přenosové připojení. - Přenosové připojení odkazuje na logický vztah mezi klientem a serverem, který udržuje jedno ze čtyř přenosových rozhraní API: WebSockets, server-sent events, forever frame nebo long polling. SignalR používá k vytvoření přenosového připojení rozhraní API přenos a rozhraní API přenosu závisí na existenci fyzického síťového připojení k vytvoření přenosového připojení. Přenosové připojení skončí, když ho SignalR ukončí nebo když rozhraní API přenosu zjistí, že je fyzické připojení přerušené.
- Fyzické připojení odkazuje na fyzické síťové propojení – dráty, bezdrátové signály, směrovače atd. – které usnadňují komunikaci mezi klientským počítačem a serverovým počítačem. Fyzické připojení musí být k dispozici, aby bylo možné navázat přenosové spojení, a aby bylo možné vytvořit připojení SignalR, musí být navázáno přenosové spojení. Přerušení fyzického připojení ale nemusí vždy okamžitě ukončit přenosové připojení nebo připojení SignalR, jak je vysvětleno dále v tomto tématu.
V následujícím diagramu je připojení SignalR reprezentováno vrstvou SignalR api Hubs a persistentConnection API, přenosové připojení je reprezentováno vrstvou Transports a fyzické připojení je reprezentováno čarami 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 se okamžitě neodejde, protože klient stále obsahuje informace, které potřebuje k automatickému opětovnému navázání nového přenosového připojení ke stejné adrese URL služby SignalR. V tomto scénáři se nevyžaduje žádný zásah z uživatelské aplikace a když kód klienta SignalR vytvoří nové přenosové připojení, nespustí 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ě připojení k přenosu automaticky znovu vytvoří. Obslužná rutina OnDisconnected
události se spustí na konci připojení SignalR. Připojení SignalR může končit některým z následujících způsobů:
- Pokud klient volá metodu
Stop
, odešle se na server zpráva zastavení a klient i server ukončí připojení SignalR okamžitě. - Po ztrátě připojení mezi klientem a serverem se klient pokusí znovu připojit a server počká, až se klient znovu připojí. Pokud pokusy o opětovné připojení nejsou úspěšné a doba časového limitu odpojení skončí, ukončí připojení SignalR klient i server. Klient se přestane pokoušet znovu připojit a server odstraní jeho reprezentaci připojení SignalR.
- Pokud se klient přestane spouštět bez možnosti volání
Stop
metody, server počká, až se klient znovu připojí, a po uplynutí časového limitu odpojení ukončí připojení SignalR. - 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. Následující části popisují podrobněji další scénáře.
Scénáře odpojení přenosu
Fyzická připojení můžou být pomalá nebo může dojít k přerušení připojení. V závislosti na faktorech, jako je délka přerušení, může dojít k vyřazení přenosového spojení. SignalR se pak pokusí znovu navázat přenosové připojení. Rozhraní API přenosového připojení někdy zjistí přerušení a zahodí přenosové připojení a SignalR zjistí, že připojení je okamžitě ztraceno. V jiných scénářích ani rozhraní API přenosového připojení ani SignalR se okamžitě nezoznají, že došlo ke ztrátě připojení. Pro všechny přenosy s výjimkou dlouhého dotazování používá klient SignalR funkci s názvem keepalive ke kontrole ztráty připojení, že přenosové rozhraní API nedokáže rozpoznat. Informace o dlouhých připojeních k dotazování najdete v části Vypršení časového limitu a nastavení uchování dále v tomto tématu.
Pokud je připojení neaktivní, server pravidelně odesílá klientovi paket keepalive. Od data zápisu tohoto článku je výchozí frekvence každých 10 sekund. Když klienti naslouchají těmto paketům, můžou zjistit, jestli došlo k problému s připojením. Pokud se paket keepalive nedostává 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 keepalive po delší době stále nedostává, klient předpokládá, že připojení bylo ukončeno a začne se pokoušet znovu připojit.
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 přenosu okamžitě nerozpozná. Diagram se vztahuje na následující okolnosti:
- Přenos je WebSocket, navždy rámeček nebo události odesílané serverem.
- Ve fyzickém síťovém připojení dochází k různým obdobím přerušení.
- Rozhraní API přenosu se o přerušení nedovědělo, takže SignalR spoléhá na zachování funkčnosti, která je detekuje.
Pokud klient přejde do režimu opětovného připojení, ale nemůže navázat přenosové připojení v rámci limitu časového limitu odpojení, server ukončí připojení SignalR. Když k tomu dojde, server spustí metodu centra OnDisconnected
a zařadí do fronty zprávu o odpojení, která se odešle klientovi v případě, že se klient později spravuje pro připojení. Pokud se klient pak znovu připojí, obdrží příkaz pro odpojení a zavolá metodu Stop
. V tomto scénáři se nespustí při OnReconnected
opětovném připojení klienta a OnDisconnected
není spuštěn při volání Stop
klienta . Tento scénář znázorňuje následující diagram.
Události životnosti připojení SignalR, které mohou být vyvolány v klientovi, jsou následující:
ConnectionSlow
událost klienta.Vyvolá se, když se od poslední zprávy nebo přijetí příkazu ping předá přednastavená část intervalu časového limitu keepalive. Výchozí interval upozornění časového limitu keepalive je 2/3 časového limitu keepalive. Časový limit keepalive je 20 sekund, takže se upozornění vyskytuje asi 13 sekund.
Ve výchozím nastavení server odesílá příkazy ping keepalive každých 10 sekund a klient kontroluje zachování příkazů ping přibližně každých 2 sekundy (jedna třetina rozdílu mezi hodnotou časového limitu keepalive a hodnotou upozornění upozornění časového limitu keepalive).
Pokud si rozhraní API přenosu uvědomí o odpojení, může být SignalR o odpojení informován dříve, než uplyne doba upozornění časového limitu 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á se, když (a) rozhraní API přenosu zjistí, že dojde ke ztrátě připojení, nebo (b) doba časového limitu uchování uplynula od poslední zprávy nebo přijetí příkazu ping keepalive. Kód klienta SignalR se začne znovu připojovat. Tuto událost můžete zpracovat, pokud chcete, aby vaše aplikace určitou akci řídila, když dojde ke ztrátě přenosového připojení. Výchozí doba časového limitu zachování je aktuálně 20 sekund.
Pokud se váš klientský kód pokusí volat metodu centra v době, kdy je SignalR v režimu opětovného připojení, signalR se pokusí odeslat příkaz. Většinu času takové pokusy selžou, ale v některých případech mohou uspět. U událostí odesílaných serverem, navždy 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 jeden, který používá k příjmu zpráv. Kanál používaný pro příjem je trvale otevřený a to je kanál, který je zavřený při přerušení fyzického připojení. Kanál použitý k odesílání zůstává dostupný, takže pokud se obnoví fyzické připojení, může být volání metody z klienta na server úspěšné, než se kanál příjmu znovu vytvoří. Vrácená hodnota se nepřijala, dokud SignalR znovu neotevře kanál použitý pro příjem.
Reconnected
událost klienta.Vyvolá se při opětovném publikování přenosového připojení. Obslužná rutina
OnReconnected
události v centru se spustí.Closed
událost klienta (disconnected
událost v JavaScriptu).Vyvolá se při vypršení časového limitu odpojení, když 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í, protože
Stop
metoda je volána.)
Přerušení přenosových připojení, která rozhraní API přenosu nezjistí a nezpozdí příjem nechopravovaných příkazů ping ze serveru déle, než je doba upozornění na upozornění časového limitu keepalive, nemusí způsobit vyvolání žádných 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 oznámí, že se používá připojení SignalR. Vextrémních V takovém případě můžete nakonfigurovat příkazy ping pro zachování, aby se odesílaly častěji. Další informace najdete v části Vypršení časového limitu a nastavení uchování dále v tomto tématu.
Poznámka:
Důležité: Posloupnost událostí popsaných zde není zaručená. SignalR provádí každý pokus o vyvolání událostí životnosti připojení předvídatelným způsobem podle tohoto schématu, ale existuje mnoho variací síťových událostí a mnoho způsobů, jak je zpracovávají základní komunikační architektury, jako jsou přenosová rozhraní API. Reconnected
Například událost nemusí být vyvolána při opětovném připojení klienta nebo obslužná rutina OnConnected
na serveru může běžet, když pokus o navázání připojení není úspěšný. Toto téma popisuje pouze účinky, které by obvykle vznikly za určitých typických okolností.
Scénáře odpojení klientů
V klientovi prohlížeče se kód klienta SignalR, který udržuje připojení SignalR, spouští v kontextu JavaScriptu webové stránky. To je důvod, proč 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 nebo karet prohlížeče. Když uživatel zavře okno nebo kartu prohlížeče nebo přejde na novou stránku nebo stránku aktualizuje, 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á Stop
metodu, OnDisconnected
obslužná rutina události se spustí okamžitě na serveru a klient vyvolá Closed
událost (událost je pojmenována disconnected
v JavaScriptu).
Pokud se klientská aplikace nebo počítač, na kterém běží, chybově ukončí 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 znovu připojit. 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). Tento scénář znázorňuje následující diagram.
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 může být podobný ztracenému připojení, nebo přenosové rozhraní API a SignalR můžou vědět okamžitě, že je server pryč, a SignalR se může začít znovu připojovat 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řenese do režimu online, klient se znovu připojí k obnoveného nebo novému serveru. V takovém případě připojení SignalR pokračuje v klientovi a Reconnected
událost se vyvolá. Na prvním serveru se OnDisconnected
nikdy nespustí a na novém serveru se spustí, OnReconnected
i když OnConnected
předtím nebyl pro daného klienta na daném serveru spuštěn. (Účinek je stejný, pokud se klient po restartování nebo recyklaci domény aplikace znovu připojí ke stejnému serveru, protože když server restartuje, nemá žádnou paměť předchozí aktivity připojení.) Následující diagram předpokládá, že rozhraní API přenosu bude vědět o ztraceném připojení okamžitě, takže ConnectionSlow
událost není vyvolána.
Časový limit a nastavení keepalive
Výchozí ConnectionTimeout
hodnota , DisconnectTimeout
a KeepAlive
hodnoty jsou vhodné pro většinu scénářů, ale je možné je změnit, pokud vaše prostředí má zvláštní potřeby. Pokud například vaše síťové prostředí zavře připojení, která jsou nečinná po dobu 5 sekund, budete pravděpodobně muset snížit hodnotu keepalive.
ConnectionTimeout
Toto nastavení představuje dobu, po kterou je možné nechat dopravní připojení otevřené a čekat na odpověď před zavřením a otevřením nového připojení. Výchozí hodnota je 110 sekund.
Toto nastavení platí jenom v případě, že je zakázaná funkce keepalive, která se obvykle vztahuje pouze na dlouhou přenosovou dobu dotazování. Následující diagram znázorňuje účinek tohoto nastavení na dlouhé přenosové připojení 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. Při nastavení DisconnectTimeout
KeepAlive
se hodnota automaticky nastaví na hodnotu 1/3DisconnectTimeout
.
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 hodnoty DisconnectTimeout
.
Pokud chcete nastavit obojí DisconnectTimeout
i KeepAlive
, nastavit KeepAlive
za DisconnectTimeout
. KeepAlive
Jinak se vaše nastavení přepíše, když DisconnectTimeout
se hodnota časového limitu automaticky nastaví KeepAlive
na 1/3.
Pokud chcete zakázat funkci keepalive, nastavte KeepAlive
na hodnotu null. U dlouhého přenosu dotazování je funkce keepalive automaticky zakázaná.
Změna časového limitu a nastavení zachování
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 klienta JavaScriptu, který používá vygenerovaný proxy server.
connectionSlow
Zpracujte událost tak, aby se zobrazila zpráva, jakmile SignalR o problémech s připojením ví, než přejde do režimu opětovného připojení.$.connection.hub.connectionSlow(function() { notifyUserOfConnectionProblem(); // Your function to notify user. });
reconnecting
Zpracujte událost 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
Zpracujte událost a zobrazte zprávu, když vypršel časový limit pokusu o opětovné připojení. V tomto scénáři jediným způsobem, jak znovu navázat připojení k serveru, je restartovat 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 oznámení vydáte až po vypršení časového limitu opětovného připojení, ne po normálním ukončení připojení SignalR způsobené volánímStop
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. } });
Postup průběžného opětovného připojení
V některých aplikacích můžete chtít po ztrátě připojení automaticky znovu navázat připojení a časový limit pokusu o opětovné připojení vypršel. K tomu můžete volat metodu Start
z Closed
obslužné rutiny události (disconnected
obslužná rutina události v javascriptových klientech). Před voláním Start
můžete počkat nějakou dobu, abyste se tomu vyhnuli příliš často, když server nebo fyzické připojení nejsou k dispozici. Následující ukázka kódu je pro klienta JavaScriptu využí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, který je třeba vědět v mobilních klientech, je to, že pokusy o průběžné opětovné připojení, pokud server nebo fyzické připojení nejsou k dispozici, může způsobit zbytečné vyprázdnění baterie.
Postup odpojení klienta v kódu serveru
SignalR verze 2 nemá integrované rozhraní API serveru pro odpojení klientů. V budoucnu existují plány pro přidání této funkce. 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();
};
Upozorňující
Zabezpečení – Tato metoda pro odpojení klientů ani navrhované integrované rozhraní API nebude řešit scénář hackovaných klientů se spuštěným škodlivým kódem, protože klienti se můžou znovu připojit nebo hacknutý kód může metodu stopClient
odebrat nebo změnit, co dělá. Vhodné místo pro implementaci stavové ochrany dos (DOS) není v rozhraní ani na serverové vrstvě, ale spíše ve front-endové infrastruktuře.
Zjištění důvodu odpojení
SignalR 2.1 přidá přetížení události serveru OnDisconnect
, která indikuje, jestli se klient záměrně odpojil místo vypršení časového limitu. Parametr StopCalled
je pravdivý, pokud klient připojení explicitně ukončil. Pokud v JavaScriptu došlo k chybě serveru, aby se klient odpojil, informace o chybě se klientovi předají 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); }
});