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

Linux Discussion :

Fils en "defunct" lorsque le père tarde à fermer la connexion


Sujet :

Linux

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre à l'essai
    Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Avril 2011
    Messages : 6
    Par défaut Fils en "defunct" lorsque le père tarde à fermer la connexion
    Bonjour,

    Je suis en cours de développement d'une application, et entre autre, celle-ci a besoin de recevoir des communications TCP de multiples clients.

    J'ai donc fait une boucle dans le processus parent qui accepte les connexions et les distribue à ses fils :

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    while (stop_process==0) {
    	new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
    	if (new_fd == -1) {
    		syslog(LOG_INFO,"accept");
    		exit(0);
    	}
     
    	if (!fork()) { 
    		close(sockfd); 
    		int byte_recv=0;
    		char *receive_thread = malloc(sizeof(char)*receive_size);
    		request request_in;
     
    	        request_in.status=0;
    		while (request_in.status < 5) {
    			if ((byte_recv=recv(new_fd,receive_thread,receive_size,0)) <= 0) {
    				syslog(LOG_INFO,"Erreur receive 1");close(new_fd);exit(0);
    			}
    			receive_thread[byte_recv-1]=0;
    			do_process_request(receive_thread,new_fd,&request_in);
    		}
    		free(receive_thread);
    		//sleep (5);
    		if (request_in.status == 5) { // receive finished but no response
    			send(new_fd, ok_status, 17, 0);
    			if (request_in.xml_size>0) { free (request_in.xml);}
    		}
     
    		//printf("Closing session %i\n",new_fd);
    		//sleep(1);
    		close(new_fd);
    		sleep(1); // wait for parent to close session (WHY ????).
    		exit(0);
    	}
    	//printf("Parent Closing session %i\n",new_fd);
    	if (close(new_fd) == -1) {syslog(LOG_INFO,"Error PARENT Closing session");}
    }
    Note : do_process_request traite la demande comme son nom l'indique

    Tout se passe bien en test avec un telnet, mais lorsque c'est le vrai client qui se connecte (et donc envoi toutes les infos dans un seul paquet), le processus fils passe en "defunct", le parent à l'air bloqué (il n'accepte plus de connexions et la fonction lié à SIGCHLD - et contenant un wait() - n'est pas exécutée).

    Avec un peu de debug, j'ai remarqué que le fils fermait la connexion avant le père, j'ai donc rajouté un sleep avant le close du fils (celui qui est commenté), mais cela me créait des latences de connexion.

    En mettant le sleep juste avant l'exit du fils (comme c'est le cas actuellement), cela fonctionne assez bien.

    Ma question est : pourquoi le fils passe en defunct et le père bloque sans ce sleep ?
    Pourquoi le père met il aussi longtemps pour fermer la connexion ( pour lui c'est l'instruction suivante !) ?
    Est-ce que ma structure de programme est foireuse ? ( j'ai pourtant sur ce point fait du copier/coller de programmes existants).

    Merci d'avance

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 870
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 870
    Billets dans le blog
    1
    Par défaut
    Salut

    Déjà je relève que tu crées une structures nommée "request_in". Il est probable que la fonction do_process_request la remplisse puisque plus bas tu fais un free(request_in.xml) mais uniquement si request_in.xml_size>0. Et dans le cas contraire ? Que se passe-t-il ? Fuite de mémoire ?

    Sinon je ne vois pas, dans ton père, de wait() permettant de récupérer l'état du fils. Sans ce wait, le père ne peut pas être au courant du statut du fils et donc c'est probablement la raison pour laquelle il ne peut pas en informer le scheduler qui renvoie donc "defunct" pour le fils lorsque tu fais "ps"...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre à l'essai
    Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Avril 2011
    Messages : 6
    Par défaut
    Bonjour,

    Citation Envoyé par Sve@r Voir le message
    Salut

    Déjà je relève que tu crées une structures nommée "request_in". Il est probable que la fonction do_process_request la remplisse puisque plus bas tu fais un free(request_in.xml) mais uniquement si request_in.xml_size>0. Et dans le cas contraire ? Que se passe-t-il ? Fuite de mémoire ?
    request_in est une structure allouée statiquement dans le process.
    request_in.xml n'est alloué que dans certaines conditions (paquet valide) et dans ce cas, request_in.xml_size est bien supérieur à zéro. Donc pas de fuite à ce niveau.

    Citation Envoyé par Sve@r Voir le message
    Sinon je ne vois pas, dans ton père, de wait() permettant de récupérer l'état du fils. Sans ce wait, le père ne peut pas être au courant du statut du fils et donc c'est probablement la raison pour laquelle il ne peut pas en informer le scheduler qui renvoie donc "defunct" pour le fils lorsque tu fais "ps"...
    Le wait est réalisé dans une fonction spécifique
    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
     
    void sigchld_handler(int s)
    {
            logging(5,"Son died..");
            while(waitpid(-1, NULL, WNOHANG) > 0);
    }
    [...]
    Dans main()
            struct sigaction sa;
            sa.sa_handler = sigchld_handler;
            sigemptyset(&sa.sa_mask);
            sa.sa_flags = SA_RESTART;
            if (sigaction(SIGCHLD, &sa, NULL) == -1) {
                    logging(6,"sigaction failed");
                    exit(1);
            }
    et effectivement tout ce passe bien en debug.
    Mais cette fonction n'a pas l'air d'être appelée lorsque le père ferme le socket (cf mon premier post) avant le fils.
    On dirait que le père "freeze", ou que le signal n'est plus bien routé...

    Cette question est devenue rhétorique car je suis passé sur cette partie en threads, mais je suis curieux d'avoir une explication à cette problématique (car je risque de la retrouver un jour).

    Merci pour ta réponse en tout cas.

  4. #4
    Membre émérite
    Avatar de D[r]eadLock
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    504
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 504
    Par défaut
    Je ne sais pas ce que fait logging, mais attention, il ne faut que des fonctions signal-safe dans le handler de signal (cf. man 7 signal). En particulier printf() n'est pas valable (et donc si t'as laissé le printf() du père avant le close() et que le signal intervient à ce moment => undefined behavior, i.e. ça peut effectivement freezer).

    Quand tu ajoute le sleep(1) avant le close dans le fils, c'est "normal" que tu ait de la latence, car la connexion réseau n'est coupée que sur le close() (donc une fois que celui du père et du fils sont fait).

    Pour aller plus loin, ce serait peut-être intéressant de faire un strace du père (voire de tout (-f)), car comme ça (en dehors de 'logging()'), je ne vois rien de spécial.

  5. #5
    Membre à l'essai
    Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Avril 2011
    Messages : 6
    Par défaut
    Citation Envoyé par D[r]eadLock Voir le message
    Je ne sais pas ce que fait logging, mais attention, il ne faut que des fonctions signal-safe dans le handler de signal (cf. man 7 signal). En particulier printf() n'est pas valable (et donc si t'as laissé le printf() du père avant le close() et que le signal intervient à ce moment => undefined behavior, i.e. ça peut effectivement freezer).

    [.....]
    Effectivement il y a un printf dans la fonction logging. J'ai un peu mélangé les "thread-safe" (sur lesquels je travaillais à ce moment là) et "async-signal-safe".
    De plus, de nombreux exemples (dont celui que j'ai pris) inclus un printf dans le handler de gestion du signal.

    Je ne rencontrais plus ce problème que de façon très épisodique puisque la plupart des actions étaient accomplies en multi-threads et non plus en multi-process.
    Je peux cependant tester pour valider que je n'ai plus jamais ce type d'erreur mais ça m'apparaît effectivement logique que le problème soit bien de ce type.

    Merci !

    Une liste de fonctions async-signal-safe est dispo ici : http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03

    EDIT (19/04/11) : Plus de problèmes remontés malgré les différents tests de charge et autre effectués.

+ Répondre à la discussion
Cette discussion est résolue.

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