IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Rust Discussion :

Serveur TCP détecter une deconnection


Sujet :

Rust

  1. #1
    Membre éclairé
    Avatar de Blo0d4x3
    Inscrit en
    Octobre 2003
    Messages
    593
    Détails du profil
    Informations forums :
    Inscription : Octobre 2003
    Messages : 593
    Par défaut Serveur TCP détecter une deconnection
    Bonjour,

    Je suis en train de faire un serveur. Le hic est que je n'arrive pas a détecter une déconnection. L'user rentre une phrase et le serveur lui renvoit, et, si il se déconnecte avec ctrl-c le serveur renvoit en boucle infinie cette phrase.
    La fonction en question:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    fn handle_client(mut stream: TcpStream) {
        let mut data = [0 as u8; 50]; 
        let loggin_banner = b"Login:";
     
        stream.write(loggin_banner).unwrap();
     
        while match stream.read(&mut data) {
            Ok(size) => {
     
                let s = String::from_utf8_lossy(&data);
                println!("result: {}", s);
     
                stream.write(&data[0..size]).unwrap();
                true
            },
     
            Err(e) if e.kind() == ErrorKind::ConnectionAborted => {
                println!("Client disconnected");
                false
            }
            Err(e) => {
                println!("Some other error occurred: {e}");
                false
            }
        } {}
    }

  2. #2
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    Peut-être qu'au niveau du client il devrait envoyer un message si tu arrives à intercepter le CTRL-C (SIGTERM, ...)
    ...le serveur recevrait ce message et considérerait la connexion comme étant clause.
    Maintenant si il y a un SIGSTOP/SIGKILL... ce sera plus très adapté mais voici peut-être une piste.

    EDIT

    Attention ErrorKind::ConnectionAborted doit être testé par le client d'après la doc !!

    ConnectionRefused
    The connection was refused by the remote server.

    ConnectionReset
    The connection was reset by the remote server.

    ConnectionAborted
    The connection was aborted (terminated) by the remote server.

  3. #3
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Bonjour,
    Citation Envoyé par Blo0d4x3 Voir le message
    Bonjour,
    Je suis en train de faire un serveur. Le hic est que je n'arrive pas a détecter une déconnection. L'user rentre une phrase et le serveur lui renvoit, et, si il se déconnecte avec ctrl-c le serveur renvoit en boucle infinie cette phrase.
    La fonction en question:
    Votre erreur ici est que vous devez implicitement fermer la connexion avec le client en utilisant un break, ce qui entraînera la fermeture implicite du socket. Sinon, vous rencontrerez le comportement que vous avez décrit, qui est dû au fait que si read renvoie 0 (indiquant la fermeture de la connexion par le client), le programme restera bloqué dans la boucle, essayant continuellement de lire des données à partir d'une connexion fermée. Le break est donc essentiel et important pour vous faire sortir de la boucle, ce qui permet au serveur de passer à d'autres clients ou de se terminer proprement. Vous avez donc besoin d'une autre approche voir l'exemple ci-dessous.

    Code rust : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
     
    use std::thread;
    use std::time::Duration;
    use std::io::{self, Read, Write};
    use std::net::{TcpListener, TcpStream};
     
    const BUFSIZE: usize = 512;
     
    fn handle_clients(mut stream: TcpStream) {
        let mut buffer = [0u8; BUFSIZE];
     
        loop {
            match stream.read(&mut buffer) {
                Ok(0) => {
                    /*    
                     * Si la lecture retourne 0, cela signifie que le client 
                     * a fermé la connexion
                     */
                    println!("[+]Info:Client {} déconnecté.",
                        stream.peer_addr().expect(
                        "[-]Erreur serveur connexions"),);
     
                    /*
                     * votre erreur est ici il faut une fermeture 
                     * de la connexion (implicite par le break)
                     * qui close la socket
                     */
                    break;     /* close socket    */
     
                }
                Ok(nbyte) => {
                    /*    Traitement des données reçues du client    */
                    print!(
                        "[+]Réception des données: {} {} bytes => Message:{}", 
                        stream.peer_addr().expect(
                        "[-]Erreur serveur connexions"),
                        nbyte, String::from_utf8_lossy(&buffer));
                    println!("\t Bytes = {:?}", &buffer[..nbyte]);
     
                    /*    Répond au client    */
                    if let Err(error) = stream.write_all(&buffer[..nbyte]) {
                        println!("[-]Échec de l'envoi de la réponse : {}", 
                            error);
                       break;
                    }
                }
                Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
                    /*    si le socket est non-bloquant, 
                     * continuez à écouter
                     */
                    thread::sleep(Duration::from_millis(100));
                    continue;
                }
                Err(ref error) if error.kind() == io::ErrorKind::ConnectionAborted => {
                    /*    si déconnexion du client détectée afficher    */
                    print!("[+]La connexion du client a été interrompue");
                    println!("\t Status: {}", error);
                    break;    /* close la socket    */
                }
                Err(error) => {
                    /*    Gestion(s) d'autres erreurs */
                    println!("[-]Échec de la connexion: Erreur {}", error);
                    break;
                }
            }
        }
     
        println!("Connection handler exited.");
    }
     
    fn main() -> io::Result<()> {
        let listener = TcpListener::bind("127.0.0.1:7878")?;
        println!("Serveur écoutant sur le port 7878");
     
        for stream_tcp in listener.incoming() {
            match stream_tcp {
                Ok(stream_tcp) => {
                    println!("Nouvelle connexion: {}", 
                        stream_tcp.peer_addr()
                        .expect("[-]Erreur serveur des connexions"));
     
                    /*    
                     * Spawner une nouvelle thread 
                     * pour chaque connexion client
                     */
                    thread::spawn(move || {
                        handle_clients(stream_tcp);
                    });
                }
                Err(error) => {
                    println!("[-]La connexion n'a pas été acceptée: {}", 
                    error);
                }
            }
        }
     
        Ok(())
    }


    Citation Envoyé par hurukan Voir le message
    Peut-être qu'au niveau du client il devrait envoyer un message si tu arrives à intercepter le CTRL-C (SIGTERM, ...)
    ...le serveur recevrait ce message et considérerait la connexion comme étant clause.
    Maintenant si il y a un SIGSTOP/SIGKILL... ce sera plus très adapté mais voici peut-être une piste.

    EDIT

    Attention ErrorKind::ConnectionAborted doit être testé par le client d'après la doc !!
    Attention, cette approche est incorrecte. Les signaux Unix ou Linux (comme SIGINT, SIGTERM, etc.) sont des interruptions gérées par le système d'exploitation et sont destinés aux processus locaux, c'est-à-dire aux processus exécutés sur le même système. Par leur nature même, ces signaux ne sont pas conçus pour être envoyés ou reçus à travers un réseau, car ils sont émis directement par le système d'exploitation ou par d'autres processus locaux pour notifier un processus d'événements tels qu'une demande d'interruption (par exemple, Ctrl+C pour SIGINT), la terminaison d'un processus, ou d'autres événements asynchrones.

    Un client distant ne peut pas envoyer directement un signal à un serveur, et c'est en fait une bonne chose, car cela ouvrirait une faille de sécurité majeure; n'importe qui pourrait alors; interrompre n'importe quel processus sur un système distant. De plus, les protocoles réseau tels que TCP/IP ne sont pas conçus pour transmettre des signaux au niveau du système d'exploitation. Ils sont destinés à transporter des données au niveau applicatif. La gestion des événements tels qu'une déconnexion d'un client, une erreur réseau ou la réception de données est effectuée par le serveur en utilisant des mécanismes spécifiques à ces protocoles, et non via des signaux.

    Par exemple, si un client ferme brusquement une connexion TCP en utilisant un signal, le serveur ne recevra pas de signal comme Ctrl+C du client, car ce signal est local au système du client. Cependant, le serveur peut détecter cette déconnexion soudaine grâce à une erreur réseau, telle que ErrorKind::ConnectionAborted, qui indique qu'une connexion a été interrompue de manière inattendue. En d'autres termes, cela signifie que le client a brusquement coupé la communication.


    Dans certains cas, le client peut envoyer un caractère spécial "fin de fichier" (EOF) pour indiquer qu'il souhaite fermer la connexion. Le serveur peut détecter cela en vérifiant la valeur de retour de la fonction read, qui sera égale à 0 si le client a fermé la connexion. Le serveur peut alors fermer sa propre connexion et sortir de la boucle qui gère la communication avec le client.


    En résumé, pour notifier un serveur d'événements spécifiques, un client doit utiliser des messages réseau explicites ou gérer les déconnexions via des erreurs réseau que le serveur peut détecter. La communication entre client et serveur repose sur des protocoles réseau, et non sur des signaux.

    à bientôt.

  4. #4
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    Je parlais que le client allait essayer d'intercepter un signal (en considérant que nous sommes dans un environnement POSIX compliant et que des signaux puissent être interceptés).
    Une fois ce signal intercepté, il enverrait via le réseau un message au serveur qui interpréterait ce message.

    Via un write() via une socket ou peu importe...

  5. #5
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Citation Envoyé par hurukan Voir le message
    Je parlais que le client allait essayer d'intercepter un signal (en considérant que nous sommes dans un environnement POSIX compliant et que des signaux puissent être interceptés).
    Une fois ce signal intercepté, il enverrait via le réseau un message au serveur qui interpréterait ce message.

    Via un write() via une socket ou peu importe...
    No cela est totalement inutile. Dans un schéma client-serveur, il n'est pas nécessaire, et même superflu, que le client envoie un message explicite pour signaler la fin de la connexion après une interruption via un signal comme CTRL+C (SIGINT). Cela ajoute une complexité inutile, car on impose au client l'envoi d'un message spécifique pour fermer la connexion, obligeant ainsi le serveur à gérer des commandes supplémentaires pour détecter et traiter ces messages. Cette approche complexifie la logique du serveur, alors que des mécanismes de détection de déconnexion existent déjà.

    Le serveur peut en effet détecter automatiquement la fin d'une connexion via les mécanismes intégrés au réseau, tels que :


    • Si le client ferme la connexion proprement, le serveur peut identifier la fin de la transmission et réagir en fermant la connexion de son côté.
    • Si le client se déconnecte brutalement (comme avec CTRL+C), le serveur en est informé par des mécanismes comme les timeouts ou des erreurs sur le socket (par exemple, un RST TCP pour réinitialiser la connexion) et peut également clore la connexion.

    Ainsi, la gestion explicite de la fin de connexion par un message spécifique est souvent, voire complètement inutile. Le protocole TCP, ou tout autre protocole réseau sous-jacent, est déjà conçu pour gérer la fermeture des connexions, qu'elles soient volontaires ou non. Cela permet au serveur de détecter automatiquement la déconnexion d'un client sans qu'il soit nécessaire de traiter des commandes supplémentaires. Il est donc plus judicieux d'utiliser les mécanismes propres à TCP pour simplifier les choses.

Discussions similaires

  1. Creation d'une application de Recuperation de flux video via un serveur TCP
    Par Reds93 dans le forum API standards et tierces
    Réponses: 1
    Dernier message: 28/03/2019, 16h50
  2. Réponses: 2
    Dernier message: 03/03/2017, 17h11
  3. connexion à un serveur tcp à prtir d'une page web
    Par zedlik dans le forum ASP.NET
    Réponses: 1
    Dernier message: 29/06/2009, 19h04
  4. [SQL SERVEUR]taille d'une base de donnée
    Par hirochirak dans le forum Autres SGBD
    Réponses: 2
    Dernier message: 08/01/2004, 12h07
  5. [Concept]Concept d'un serveur TCP/IP
    Par Zc dans le forum Développement
    Réponses: 8
    Dernier message: 17/01/2003, 17h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo