Présentation et gestion des événements de durée de vie des connexions dans SignalR

Avertissement

Cette documentation ne concerne pas la dernière version de SignalR. Consultez ASP.NET Core SignalR.

Cet article fournit une vue d’ensemble des événements de connexion, de reconnexion et de déconnexion SignalR que vous pouvez gérer, ainsi que des paramètres de délai d’expiration et de maintien que vous pouvez configurer.

L’article suppose que vous avez déjà une certaine connaissance des événements SignalR et de durée de vie de connexion. Pour une présentation de SignalR, consultez Présentation de SignalR. Pour obtenir la liste des événements de durée de vie de connexion, consultez les ressources suivantes :

Versions logicielles utilisées dans cette rubrique

Versions précédentes de cette rubrique

Pour plus d’informations sur les versions antérieures de SignalR, consultez Anciennes versions de SignalR.

Questions et commentaires

Laissez vos commentaires sur la façon dont vous avez aimé ce tutoriel et sur ce que nous pourrions améliorer dans les commentaires en bas de la page. Si vous avez des questions qui ne sont pas directement liées au tutoriel, vous pouvez les publier sur le forum ASP.NET SignalR ou StackOverflow.com.

Vue d’ensemble

Cet article contient les sections suivantes :

Les liens vers les rubriques de référence de l’API sont vers la version .NET 4.5 de l’API. Si vous utilisez .NET 4, consultez la version .NET 4 des rubriques de l’API.

Terminologie et scénarios de durée de vie de connexion

Le OnReconnected gestionnaire d’événements dans un hub SignalR peut s’exécuter directement après OnConnected , mais pas après OnDisconnected pour un client donné. La raison pour laquelle vous pouvez avoir une reconnexion sans déconnexion est qu’il existe plusieurs façons d’utiliser le mot « connexion » dans SignalR.

Connexions SignalR, connexions de transport et connexions physiques

Cet article fait la distinction entre les connexions SignalR, les connexions de transport et les connexions physiques :

  • La connexion SignalR fait référence à une relation logique entre un client et une URL de serveur, gérée par l’API SignalR et identifiée de manière unique par un ID de connexion. Les données relatives à cette relation sont conservées par SignalR et sont utilisées pour établir une connexion de transport. La relation se termine et SignalR supprime les données lorsque le client appelle la Stop méthode ou qu’une limite de délai d’attente est atteinte pendant que SignalR tente de rétablir une connexion de transport perdue.
  • La connexion de transport fait référence à une relation logique entre un client et un serveur, gérée par l’une des quatre API de transport : WebSockets, événements envoyés par le serveur, frame pour toujours ou interrogation longue. SignalR utilise l’API de transport pour créer une connexion de transport, et l’API de transport dépend de l’existence d’une connexion réseau physique pour créer la connexion de transport. La connexion de transport prend fin lorsque SignalR l’arrête ou lorsque l’API de transport détecte que la connexion physique est rompue.
  • La connexion physique fait référence aux liaisons réseau physiques : câbles, signaux sans fil, routeurs, etc. - qui facilitent la communication entre un ordinateur client et un ordinateur serveur. La connexion physique doit être présente pour établir une connexion de transport, et une connexion de transport doit être établie pour établir une connexion SignalR. Toutefois, la rupture de la connexion physique ne met pas toujours immédiatement fin à la connexion de transport ou à la connexion SignalR, comme expliqué plus loin dans cette rubrique.

Dans le diagramme suivant, la connexion SignalR est représentée par l’API Hubs et la couche SignalR de l’API PersistentConnection, la connexion de transport est représentée par la couche Transports et la connexion physique est représentée par les lignes entre le serveur et les clients.

Diagramme de l’architecture SignalR

Lorsque vous appelez la Start méthode dans un client SignalR, vous fournissez au code client SignalR toutes les informations dont il a besoin pour établir une connexion physique à un serveur. Le code client SignalR utilise ces informations pour effectuer une requête HTTP et établir une connexion physique qui utilise l’une des quatre méthodes de transport. Si la connexion de transport échoue ou si le serveur échoue, la connexion SignalR ne disparaît pas immédiatement, car le client dispose toujours des informations dont il a besoin pour rétablir automatiquement une nouvelle connexion de transport à la même URL SignalR. Dans ce scénario, aucune intervention de l’application utilisateur n’est impliquée et lorsque le code client SignalR établit une nouvelle connexion de transport, il ne démarre pas une nouvelle connexion SignalR. La continuité de la connexion SignalR se reflète dans le fait que l’ID de connexion, qui est créé lorsque vous appelez la Start méthode, ne change pas.

Le OnReconnected gestionnaire d’événements sur le hub s’exécute lorsqu’une connexion de transport est automatiquement rétablie après avoir été perdue. Le OnDisconnected gestionnaire d’événements s’exécute à la fin d’une connexion SignalR. Une connexion SignalR peut se terminer de l’une des manières suivantes :

  • Si le client appelle la Stop méthode, un message d’arrêt est envoyé au serveur et le client et le serveur mettez immédiatement fin à la connexion SignalR.
  • Une fois la connectivité entre le client et le serveur perdue, le client tente de se reconnecter et le serveur attend que le client se reconnecte. Si les tentatives de reconnexion échouent et que le délai de déconnexion se termine, le client et le serveur mettent fin à la connexion SignalR. Le client cesse d’essayer de se reconnecter et le serveur supprime sa représentation de la connexion SignalR.
  • Si le client cesse de s’exécuter sans avoir la possibilité d’appeler la Stop méthode, le serveur attend que le client se reconnecte, puis met fin à la connexion SignalR après la période de délai de déconnexion.
  • Si le serveur cesse de s’exécuter, le client tente de se reconnecter (recréer la connexion de transport), puis met fin à la connexion SignalR après le délai de déconnexion.

Lorsqu’il n’y a aucun problème de connexion et que l’application utilisateur met fin à la connexion SignalR en appelant la Stop méthode, la connexion SignalR et la connexion de transport commencent et se terminent à peu près en même temps. Les sections suivantes décrivent plus en détail les autres scénarios.

Scénarios de déconnexion du transport

Les connexions physiques peuvent être lentes ou il peut y avoir des interruptions de connectivité. Selon des facteurs tels que la longueur de l’interruption, la connexion de transport peut être supprimée. SignalR tente ensuite de rétablir la connexion de transport. Parfois, l’API de connexion de transport détecte l’interruption et supprime la connexion de transport, et SignalR découvre immédiatement que la connexion est perdue. Dans d’autres scénarios, ni l’API de connexion de transport ni SignalR ne prennent immédiatement conscience de la perte de connectivité. Pour tous les transports, à l’exception de l’interrogation longue, le client SignalR utilise une fonction appelée keepalive pour case activée en cas de perte de connectivité que l’API de transport ne peut pas détecter. Pour plus d’informations sur les connexions d’interrogation longues, consultez Paramètres de délai d’expiration et de conservation plus loin dans cette rubrique.

Lorsqu’une connexion est inactive, le serveur envoie régulièrement un paquet keepalive au client. À la date d’écriture de cet article, la fréquence par défaut est toutes les 10 secondes. En écoutant ces paquets, les clients peuvent déterminer s’il existe un problème de connexion. Si un paquet keepalive n’est pas reçu comme prévu, le client suppose qu’il existe des problèmes de connexion tels que des lenteurs ou des interruptions. Si le keepalive n’est toujours pas reçu après une période plus longue, le client suppose que la connexion a été supprimée et qu’il commence à essayer de se reconnecter.

Le diagramme suivant illustre les événements client et serveur qui sont déclenchés dans un scénario classique lorsqu’il existe des problèmes de connexion physique qui ne sont pas immédiatement reconnus par l’API de transport. Le diagramme s’applique aux circonstances suivantes :

  • Le transport est WebSockets, frame forever ou événements envoyés par le serveur.
  • Il existe différentes périodes d’interruption dans la connexion réseau physique.
  • L’API de transport n’est pas consciente des interruptions. SignalR s’appuie donc sur la fonctionnalité keepalive pour les détecter.

Déconnexions de transport

Si le client passe en mode de reconnexion mais ne parvient pas à établir une connexion de transport dans le délai d’attente de déconnexion, le serveur met fin à la connexion SignalR. Dans ce cas, le serveur exécute la méthode du OnDisconnected hub et met en file d’attente un message de déconnexion à envoyer au client au cas où le client parvient à se connecter ultérieurement. Si le client se reconnecte, il reçoit la commande de déconnexion et appelle la Stop méthode. Dans ce scénario, OnReconnected n’est pas exécuté lorsque le client se reconnecte et OnDisconnected n’est pas exécuté lorsque le client appelle Stop. Le diagramme suivant illustre ce scénario.

Interruptions de transport - délai d’attente du serveur

Les événements de durée de vie de connexion SignalR qui peuvent être déclenchés sur le client sont les suivants :

  • ConnectionSlow événement client.

    Déclenché lorsqu’une proportion prédéfinie de la période de délai d’attente de maintien s’est écoulée depuis la réception du dernier message ou du dernier ping de maintien. La période d’avertissement de délai d’attente par défaut est de 2/3 du délai d’expiration de la durée de maintien. Le délai d’attente keepalive étant de 20 secondes, l’avertissement se produit à environ 13 secondes.

    Par défaut, le serveur envoie des pings keepalive toutes les 10 secondes, et le client vérifie les pings de maintien environ toutes les 2 secondes (un tiers de la différence entre la valeur de délai d’expiration keepalive et la valeur d’avertissement de délai d’attente de maintien).

    Si l’API de transport prend connaissance d’une déconnexion, SignalR peut être informé de la déconnexion avant que la période d’avertissement de délai d’attente de maintien passe. Dans ce cas, l’événement ConnectionSlow n’est pas déclenché et SignalR accède directement à l’événement Reconnecting .

  • Reconnecting événement client.

    Déclenché lorsque (a) l’API de transport détecte que la connexion est perdue, ou (b) que le délai d’attente de maintien s’est écoulé depuis la réception du dernier message ou du dernier ping de maintien. Le code client SignalR commence à essayer de se reconnecter. Vous pouvez gérer cet événement si vous souhaitez que votre application prenne des mesures en cas de perte de connexion de transport. La période de délai d’attente par défaut est actuellement de 20 secondes.

    Si votre code client tente d’appeler une méthode Hub alors que SignalR est en mode de reconnexion, SignalR tente d’envoyer la commande. La plupart du temps, de telles tentatives échouent, mais dans certaines circonstances, elles peuvent aboutir. Pour les événements envoyés par le serveur, les trames permanentes et les longs transports d’interrogation, SignalR utilise deux canaux de communication, un que le client utilise pour envoyer des messages et un autre qu’il utilise pour recevoir des messages. Le canal utilisé pour la réception est celui ouvert en permanence, et c’est celui qui est fermé lorsque la connexion physique est interrompue. Le canal utilisé pour l’envoi reste disponible. Par conséquent, si la connectivité physique est restaurée, un appel de méthode du client au serveur peut réussir avant que le canal de réception ne soit rétabli. La valeur de retour n’est pas reçue tant que SignalR ne ré-ouvre pas le canal utilisé pour la réception.

  • Reconnected événement client.

    Déclenché lorsque la connexion de transport est rétablie. Le OnReconnected gestionnaire d’événements dans le hub s’exécute.

  • Closed événement client (disconnected événement en JavaScript).

    Déclenché lorsque le délai d’expiration du délai de déconnexion expire alors que le code client SignalR tente de se reconnecter après avoir perdu la connexion de transport. Le délai de déconnexion par défaut est de 30 secondes. (Cet événement est également déclenché lorsque la connexion se termine, car la Stop méthode est appelée.)

Les interruptions de connexion de transport qui ne sont pas détectées par l’API de transport et qui ne retardent pas la réception des pings de maintien à partir du serveur pendant plus longtemps que la période d’avertissement de délai d’attente de maintien peuvent ne pas entraîner le déclencher d’événements de durée de vie de connexion.

Certains environnements réseau ferment délibérément les connexions inactives, et une autre fonction des paquets keepalive est d’aider à empêcher cela en faisant savoir à ces réseaux qu’une connexion SignalR est en cours d’utilisation. Dans les cas extrêmes, la fréquence par défaut des pings keepalive peut ne pas être suffisante pour empêcher les connexions fermées. Dans ce cas, vous pouvez configurer des pings keepalive pour qu’ils soient envoyés plus souvent. Pour plus d’informations, consultez Paramètres de délai d’expiration et de maintien plus loin dans cette rubrique.

Notes

Important : la séquence d’événements décrite ici n’est pas garantie. SignalR tente à chaque fois de déclencher des événements de durée de vie de connexion de manière prévisible selon ce schéma, mais il existe de nombreuses variantes des événements réseau et de nombreuses façons dont les infrastructures de communication sous-jacentes, telles que les API de transport, les gèrent. Par exemple, l’événement Reconnected peut ne pas être déclenché lorsque le client se reconnecte, ou le OnConnected gestionnaire sur le serveur peut s’exécuter lorsque la tentative d’établissement d’une connexion échoue. Cette rubrique décrit uniquement les effets qui seraient normalement produits par certaines circonstances typiques.

Scénarios de déconnexion du client

Dans un client de navigateur, le code client SignalR qui gère une connexion SignalR s’exécute dans le contexte JavaScript d’une page web. C’est pourquoi la connexion SignalR doit prendre fin lorsque vous naviguez d’une page à l’autre, et c’est pourquoi vous avez plusieurs connexions avec plusieurs ID de connexion si vous vous connectez à partir de plusieurs fenêtres ou onglets de navigateur. Lorsque l’utilisateur ferme une fenêtre ou un onglet de navigateur, ou accède à une nouvelle page ou actualise la page, la connexion SignalR se termine immédiatement, car le code client SignalR gère cet événement de navigateur pour vous et appelle la Stop méthode. Dans ces scénarios, ou dans n’importe quelle plateforme cliente lorsque votre application appelle la Stop méthode, le OnDisconnected gestionnaire d’événements s’exécute immédiatement sur le serveur et le client déclenche l’événement Closed (l’événement est nommé disconnected en JavaScript).

Si une application cliente ou l’ordinateur sur lequel elle s’exécute se bloque ou se met en veille (par exemple, lorsque l’utilisateur ferme l’ordinateur portable), le serveur n’est pas informé de ce qui s’est passé. Pour autant que le serveur le sache, la perte du client peut être due à une interruption de connectivité et le client peut essayer de se reconnecter. Par conséquent, dans ces scénarios, le serveur attend de donner au client une chance de se reconnecter et OnDisconnected ne s’exécute pas tant que le délai de déconnexion n’a pas expiré (environ 30 secondes par défaut). Le diagramme suivant illustre ce scénario.

Défaillance de l’ordinateur client

Scénarios de déconnexion du serveur

Lorsqu’un serveur est hors connexion, il redémarre, échoue, le domaine d’application se recycle, etc. -- le résultat peut être similaire à une connexion perdue, ou l’API de transport et SignalR peuvent savoir immédiatement que le serveur a disparu, et SignalR peut commencer à essayer de se reconnecter sans déclencher l’événement ConnectionSlow . Si le client passe en mode de reconnexion, si le serveur récupère ou redémarre, ou si un nouveau serveur est mis en ligne avant l’expiration du délai d’expiration de la déconnexion, le client se reconnecte au nouveau serveur ou au nouveau serveur. Dans ce cas, la connexion SignalR continue sur le client et l’événement Reconnected est déclenché. Sur le premier serveur, OnDisconnected n’est jamais exécuté, et sur le nouveau serveur, est exécuté bien OnReconnectedOnConnected que n’ait jamais été exécuté pour ce client sur ce serveur auparavant. (L’effet est le même si le client se reconnecte au même serveur après un redémarrage ou un recyclage du domaine d’application, car lorsque le serveur redémarre, il n’a aucune mémoire de l’activité de connexion précédente.) Le diagramme suivant suppose que l’API de transport prend immédiatement connaissance de la connexion perdue, de sorte que l’événement ConnectionSlow n’est pas déclenché.

Défaillance et reconnexion du serveur

Si un serveur n’est pas disponible dans le délai de déconnexion, la connexion SignalR se termine. Dans ce scénario, l’événement Closed (disconnected dans les clients JavaScript) est déclenché sur le client, mais OnDisconnected n’est jamais appelé sur le serveur. Le diagramme suivant suppose que l’API de transport ne prend pas connaissance de la connexion perdue, donc elle est détectée par la fonctionnalité de maintien de SignalR et l’événement ConnectionSlow est déclenché.

Échec du serveur et délai d’expiration

Paramètres de délai d’expiration et de maintien

Les valeurs par défaut ConnectionTimeout, DisconnectTimeoutet KeepAlive conviennent à la plupart des scénarios, mais peuvent être modifiées si votre environnement a des besoins spéciaux. Par exemple, si votre environnement réseau ferme les connexions inactives pendant 5 secondes, vous devrez peut-être diminuer la valeur keepalive.

ConnectionTimeout

Ce paramètre représente le temps nécessaire pour laisser une connexion de transport ouverte et attendre une réponse avant de la fermer et d’ouvrir une nouvelle connexion. La valeur par défaut est 110 secondes.

Ce paramètre s’applique uniquement lorsque la fonctionnalité keepalive est désactivée, ce qui s’applique normalement uniquement au transport d’interrogation long. Le diagramme suivant illustre l’effet de ce paramètre sur une connexion de transport d’interrogation longue.

Connexion de transport d’interrogation longue

DisconnectTimeout

Ce paramètre représente le temps d’attente après la perte d’une connexion de transport avant de déclencher l’événement Disconnected . La valeur par défaut est de 30 secondes. Lorsque vous définissez DisconnectTimeout, KeepAlive est automatiquement défini sur 1/3 de la DisconnectTimeout valeur.

KeepAlive

Ce paramètre représente le temps d’attente avant d’envoyer un paquet keepalive via une connexion inactive. La valeur par défaut est 10 secondes. Cette valeur ne doit pas dépasser 1/3 de la DisconnectTimeout valeur.

Si vous souhaitez définir à la fois DisconnectTimeout et KeepAlive, définissez KeepAlive après DisconnectTimeout. Dans le cas contraire, votre KeepAlive paramètre sera remplacé lorsque DisconnectTimeout la valeur est automatiquement définie KeepAlive sur 1/3 de la valeur du délai d’expiration.

Si vous souhaitez désactiver la fonctionnalité keepalive, définissez sur KeepAlive null. La fonctionnalité Keepalive est automatiquement désactivée pour le transport d’interrogation long.

Comment modifier les paramètres de délai d’expiration et de maintien

Pour modifier les valeurs par défaut de ces paramètres, définissez-les Application_Start dans votre fichier Global.asax , comme illustré dans l’exemple suivant. Les valeurs indiquées dans l’exemple de code sont les mêmes que les valeurs par défaut.

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();
}

Comment informer l’utilisateur des déconnexions

Dans certaines applications, vous pouvez afficher un message à l’utilisateur en cas de problèmes de connectivité. Vous disposez de plusieurs options pour savoir comment et quand effectuer cette opération. Les exemples de code suivants concernent un client JavaScript à l’aide du proxy généré.

  • Gérez l’événement connectionSlow pour afficher un message dès que SignalR a connaissance de problèmes de connexion, avant qu’il ne passe en mode de reconnexion.

    $.connection.hub.connectionSlow(function() {
        notifyUserOfConnectionProblem(); // Your function to notify user.
    });
    
  • Gérez l’événement reconnecting pour afficher un message lorsque SignalR est conscient d’une déconnexion et passe en mode de reconnexion.

    $.connection.hub.reconnecting(function() {
        notifyUserOfTryingToReconnect(); // Your function to notify user.
    });
    
  • Gérez l’événement disconnected pour afficher un message lorsqu’une tentative de reconnexion a expiré. Dans ce scénario, la seule façon de rétablir une connexion avec le serveur consiste à redémarrer la connexion SignalR en appelant la Start méthode, ce qui créera un NOUVEL ID de connexion. L’exemple de code suivant utilise un indicateur pour vous assurer que vous émettez la notification uniquement après un délai de reconnexion, et non après une fin normale de la connexion SignalR provoquée par l’appel de la Stop méthode.

    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.
        }
    });
    

Comment se reconnecter en continu

Dans certaines applications, vous pouvez rétablir automatiquement une connexion une fois qu’elle a été perdue et que la tentative de reconnexion a expiré. Pour ce faire, vous pouvez appeler la Start méthode à partir de votre Closed gestionnaire d’événements (disconnected gestionnaire d’événements sur les clients JavaScript). Vous pouvez attendre un certain temps avant d’appeler Start afin d’éviter de le faire trop fréquemment lorsque le serveur ou la connexion physique ne sont pas disponibles. L’exemple de code suivant concerne un client JavaScript utilisant le proxy généré.

$.connection.hub.disconnected(function() {
   setTimeout(function() {
       $.connection.hub.start();
   }, 5000); // Restart connection after 5 seconds.
});

Un problème potentiel à connaître dans les clients mobiles est que les tentatives de reconnexion continue lorsque le serveur ou la connexion physique n’est pas disponible peuvent entraîner une décharge inutile de la batterie.

Comment déconnecter un client dans le code serveur

SignalR version 2 ne dispose pas d’API de serveur intégrée pour déconnecter les clients. Il est prévu d’ajouter cette fonctionnalité à l’avenir. Dans la version actuelle de SignalR, le moyen le plus simple de déconnecter un client du serveur consiste à implémenter une méthode de déconnexion sur le client et à appeler cette méthode à partir du serveur. L’exemple de code suivant montre une méthode de déconnexion pour un client JavaScript à l’aide du proxy généré.

var myHubProxy = $.connection.myHub
myHubProxy.client.stopClient = function() {
    $.connection.hub.stop();
};

Avertissement

Sécurité : ni cette méthode de déconnexion des clients ni l’API intégrée proposée ne répondent au scénario de clients piratés qui exécutent du code malveillant, car les clients peuvent se reconnecter ou le code piraté peut supprimer la stopClient méthode ou modifier son action. L’emplacement approprié pour implémenter la protection par déni de service avec état (DOS) n’est pas dans l’infrastructure ou la couche serveur, mais plutôt dans l’infrastructure frontale.

Détection de la raison d’une déconnexion

SignalR 2.1 ajoute une surcharge à l’événement serveur OnDisconnect qui indique si le client s’est délibérément déconnecté au lieu d’expirer. Le StopCalled paramètre a la valeur true si le client a explicitement fermé la connexion. En JavaScript, si une erreur de serveur a conduit le client à se déconnecter, les informations d’erreur sont transmises au client en tant que $.connection.hub.lastError.

Code du serveur C# : stopCalled paramètre

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);
}

Code client JavaScript : accès lastError dans l’événement disconnect .

$.connection.hub.disconnected(function () {
    if ($.connection.hub.lastError) 
        { alert("Disconnected. Reason: " +  $.connection.hub.lastError.message); }
});