Sdílet prostřednictvím


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í:

Verze softwaru používané v tomto tématu

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.

Diagram architektury SignalR

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.

Odpojení přenosu

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í Stopklienta . Tento scénář znázorňuje následující diagram.

Přerušení přenosu – vypršení časového limitu serveru

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 na Reconnecting 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.

Selhání klientského počítače

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.

Selhání serveru a opětovné připojení Pokud se server během časového limitu odpojení nedostupní, připojení SignalR skončí. V tomto scénáři se u klienta vyvolá událost Uzavřená (odpojená v klientech JavaScriptu), ale onDisconnected se na serveru nikdy nevolá. Následující diagram předpokládá, že rozhraní API přenosu neví o ztraceném připojení, takže ho detekuje funkce keepalive signalR a vyvolá se událost ConnectionSlow.

Selhání serveru a vypršení časového limitu

Časový limit a nastavení keepalive

Výchozí ConnectionTimeouthodnota , DisconnectTimeouta 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í.

Dlouhé připojení přenosu cyklického 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í DisconnectTimeoutKeepAlive 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ím Start 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ím Stop 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); }
});