Vysvětlení a zpracování událostí doby života připojení v SignalR 1.x
Upozornění
Tato dokumentace není určená pro nejnovější verzi služby 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 zachování, které můžete nakonfigurovat.
Článek předpokládá, že už máte nějaké znalosti o signalR a událostech doby života připojení. Úvod ke službě SignalR najdete v tématu SignalR – Přehled – Začínáme. Seznamy událostí doby života připojení najdete v následujících zdrojích informací:
Přehled
Tento článek obsahuje následující části:
Odkazy na témata referenčních informací k 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 doby života připojení a scénáře
Obslužná rutina OnReconnected
události v centru SignalR Hub se může pro daného klienta spustit přímo po OnConnected
, ale ne po OnDisconnected
ní. Důvodem, proč můžete mít opětovné připojení bez odpojení, je, že v SignalR se slovo "připojení" používá několika způsoby.
Připojení SignalR, přenosová připojení a fyzická připojení
Tento článek rozlišuje mezi připojeními SignalR, přenosovými připojeními a fyzickými připojeními:
- Připojení SignalR označuje logický vztah mezi klientem a adresou URL serveru, který udržuje rozhraní SignalR API a jednoznačně identifikovaný ID připojení. Data o tomto vztahu uchovává služba SignalR a používají se k vytvoření přenosového připojení. Relace se ukončí a Služba SignalR odstraní data, když klient zavolá metodu
Stop
nebo dojde k dosažení limitu č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ř rozhraní API pro přenos: 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 služba SignalR ukončí nebo když rozhraní API pro přenos zjistí, že je fyzické připojení 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 a serverovým počítačem. Aby bylo možné vytvořit dopravní připojení, musí existovat fyzické připojení a aby bylo možné vytvořit připojení SignalR, musí být vytvořeno dopravní připojení. Přerušením fyzického připojení však nedojde vždy k okamžitému ukončení přenosového 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 vrstvou Hubs API a PersistentConnection API SignalR, 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 klientskému kódu služby SignalR všechny informace, 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 dojde k selhání přenosového připojení nebo selhání serveru, připojení SignalR okamžitě nezmizí, protože klient stále má informace potřebné k automatickému opětovnému vytvoření nového přenosového připojení na stejnou adresu URL služby SignalR. V tomto scénáři není zapojen žádný zásah z uživatelské aplikace a když kód klienta SignalR naváže 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í při automatickém opětovném navázání přenosového připojení po ztrátě. 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 počká, až se klient znovu připojí. Pokud jsou pokusy o opětovné připojení neúspěšné a skončí časový limit odpojení, klient i server připojení SignalR ukončí. 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, aniž by měl možnost volat metodu
Stop
, server počká, až se klient znovu připojí, a po uplynutí časového limitu odpojení ukončí připojení SignalR. - Pokud se server zastaví, 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číná a končí přibližně ve stejnou dobu. Další scénáře jsou podrobněji popsané 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í přerušeno. SignalR se pak pokusí znovu navázat přenosové připojení. V některých případech rozhraní API pro přenosové připojení přerušení zjistí a přeruší ho a signalR okamžitě zjistí, že došlo ke ztrátě připojení. V jiných scénářích rozhraní API pro připojení přenosu ani SignalR okamžitě nepozná, ž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í, kterou rozhraní API pro přenos nedokáže rozpoznat. Informace o dlouhých dotazovacích připojeních najdete v části Nastavení časového limitu a udržová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 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 pomalé připojení nebo přerušení. Pokud se 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 nerozpozná okamžitě. Diagram se vztahuje na následující okolnosti:
- Přenosem jsou události WebSocket, forever frame nebo události odeslané serverem.
- V připojení k fyzické síti dochází k různým obdobím přerušení.
- Rozhraní API pro přenos si přerušení neuvědomuje, a proto signalR spoléhá při jejich zjišťování 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í do fronty pro případ, že se klient později připojí. Pokud se klient znovu připojí, obdrží 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é můžou být vyvolány na klientovi, jsou následující:
ConnectionSlow
událost klienta.Vyvolá se, když uplynula přednastavená část časového limitu keepalive od přijetí poslední zprávy nebo keepalive ping. 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á keepalive ping každých 10 sekund a klient kontroluje keepalive ping přibližně každé 2 sekundy (jedna třetina rozdílu mezi hodnotou časového limitu keepalive a hodnotou upozornění na časový limit keepalive).
Pokud rozhraní API pro přenos zjistí, že došlo k odpojení, signalR může být o odpojení informována před uplynutím období upozornění na časový limit uchování. V takovém případě by se
ConnectionSlow
událost nevyvolá a služba SignalR by přešla přímo na událostReconnecting
.Reconnecting
událost klienta.Vyvolá se, když (a) rozhraní API pro přenos zjistí, že došlo ke ztrátě připojení, nebo (b) uplynul časový limit keepalive od přijetí poslední zprávy nebo keepalive ping. Kód klienta SignalR se začne pokoušet o opětovné připojení. Tuto událost můžete zpracovat, pokud chcete, aby vaše aplikace při ztrátě přenosového připojení provedla nějakou akci. Výchozí časový limit keepalive je aktuálně 20 sekund.
Pokud se váš klientský kód pokusí volat metodu centra, zatímco je SignalR v režimu opětovného připojení, SignalR se pokusí odeslat příkaz . Ve většině případů takové pokusy selžou, ale za určitých okolností můžou být úspěšné. U událostí odeslaných serverem, nekonečně dlouhou dobu 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řijímání zpráv. Kanál používaný k příjmu 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ý k 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 příjmového kanálu. Vrácená hodnota by nebyla přijata, dokud služba 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í 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í, 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í, protože
Stop
je volána metoda.)
Přerušení přenosového připojení, která rozhraní API pro přenos nezjistí a nezpozdí příjem keepalive ping ze serveru o delší dobu, než je období upozornění na vypršení časového limitu keepalive, nemusí způsobit žádné události doby života připojení.
Některá síťová prostředí záměrně ukončují nečinná připojení a další funkcí keepalive paketů je pomoct tomu zabránit tím, že těmto sítím oznámí, ž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 s průběžným odesíláním odesílaly častěji. Další informace najdete v části Nastavení časového limitu a udržování dál v tomto tématu.
Poznámka
Důležité
Posloupnost zde popsaných událostí není zaručena. SignalR se podle tohoto schématu pokouší vyvolat události doby života 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í. Událost například nemusí být vyvolána, Reconnected
když se klient znovu připojí, nebo OnConnected
může být spuštěna obslužná rutina na serveru, pokud pokus o navázání připojení není úspěšný. Toto téma popisuje pouze efekty, které by normálně vznikly za určitých typických okolností.
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 musí připojení SignalR končit, když přejdete z jedné stránky na jinou, a proto máte více připojení s několika 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 zpracuje událost prohlížeče za vás a zavolá 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 dal klientovi šanci se 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ě připojení SignalR pokračuje na klientovi a Reconnected
událost se vyvolá. 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 nikdy předtím 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ěť pro 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 během časového limitu odpojení není dostupný, připojení SignalR se ukončí. V tomto scénáři je událost (disconnected
v klientech JavaScriptu) vyvolána na klientovi, Closed
ale OnDisconnected
na serveru se nikdy nevolá. Následující diagram předpokládá, že rozhraní API pro přenos se nedovědá o ztraceném připojení, takže ho detekuje funkce zachování služby SignalR a ConnectionSlow
vyvolá se událost.
Nastavení vypršení časového limitu a udržování
Výchozí ConnectionTimeout
hodnoty , DisconnectTimeout
a KeepAlive
jsou vhodné pro většinu scénářů, ale pokud má vaše prostředí zvláštní potřeby, můžete je změnit. 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 se má nechat připojení k přenosu otevřené a čekat na odpověď, než ho zavřete a otevřete nové připojení. Výchozí hodnota je 110 sekund.
Toto nastavení platí pouze v případě, že je funkce uchování zakázané, což obvykle platí pouze pro dlouhý přenos dotazování. Následující diagram znázorňuje vliv tohoto nastavení na dlouhý přenosový spoj 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
nastaví se automaticky 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 i DisconnectTimeout
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 funkci keepalive zakázat, nastavte KeepAlive
na hodnotu null. Funkce keepalive je pro dlouhý přenos dotazování automaticky zakázaná.
Jak změnit nastavení časového limitu a zachování časového limitu
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é ve vzorové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);
}
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, který používá vygenerovaný proxy server.
connectionSlow
Zpracování události 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
Zpracování události zobrazí zprávu, 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 zobrazí zprávu, když vyprší časový limit pokusu o opětovné připojení. V tomto scénáři je jediným způsobem, jak znovu navázat připojení k serveru, 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ý zajišťuje, že vydáte oznámení až po vypršení časového limitu opětovného připojení, ne po normálním ukončení připojení SignalR způsobeném 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. } });
Jak se průběžně 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ůže být vhodné nějakou dobu počkat, abyste se vyhnuli příliš častému provádění, když server nebo fyzické připojení není k dispozici. Následující ukázka kódu je určená pro javascriptového klienta, který používá 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 průběžné pokusy o opětovné připojení, když server nebo fyzické připojení není k dispozici, můžou způsobit zbytečné vybití baterie.
Jak odpojit klienta v kódu serveru
SignalR verze 1.1.1 nemá integrované rozhraní API serveru pro odpojování klientů. V budoucnu plánujeme tuto funkci přidat. V aktuální verzi služby SignalR je nejjednodušší způsob, jak odpojit klienta od serveru, implementovat na klientovi metodu disconnect a tuto metodu zavolat ze serveru. Následující ukázka kódu ukazuje metodu odpojení pro javascriptového klienta pomocí vygenerovaného proxy serveru.
var myHubProxy = $.connection.myHub
myHubProxy.client.stopClient = function() {
$.connection.hub.stop();
};
Upozornění
Zabezpečení – Tato metoda odpojení klientů ani navrhované integrované rozhraní API neřeší scénář napadených klientů, na kterých běží škodlivý kód, protože se klienti mohou znovu připojit nebo napadený kód může metodu stopClient
odebrat nebo změnit to, co dělá. Vhodné místo pro implementaci stavové ochrany dos (DoS) není v architektuře nebo vrstvě serveru, ale spíše ve front-endové infrastruktuře.