[Serveur en C ] pb de processus zombies

pb de processus zombies [Serveur en C ] - C - Programmation

Marsh Posté le 11-10-2004 à 20:10:55    

Coucou !
 
Voila je dois développer un programme perso qui est un serveur qui attend des connections sur le port prédéfini et qui envoie un fichier texte au client qui se connecte , puis déconnecte le client.
Le serveur est fait pour ne jamais s'arreter(boucle infinie) et pour marcher en parallele (traiter plusieurs client en meme tps).
Tres scolaire et tres simple en théorie :).
 
Mon probleme :
 
Je cré un processus fils qui traitera la demande d'un client qui se connecte (avec fork() ).
Mon probleme est que quand je lance mon serveur, chaque processus fils terminé laisse un "zombie" une trace de lui dans la liste des processus.
 
Il faudrait que le programme principal, donc le pere attende la fin du fils qui traite la demande mais là cela ne serait plus un serveur parallele.
 
Comment puis je faire? je développe en C sous Linux.

Reply

Marsh Posté le 11-10-2004 à 20:10:55   

Reply

Marsh Posté le 11-10-2004 à 20:25:13    

pourquoi pas les thread ?
 
tu veux virer tes zombies ? il te faut faire des wait ...

Reply

Marsh Posté le 11-10-2004 à 20:42:54    

Tu peux également faire le tout dans une seul thread, dans un seul processus, en utilisant select pour être en attente de tes clients.  
 
C'est ce principe qu'utilisent beaucoup d'outils (mais en utilisant d'autres APIs que select, qui est un peu trop limité, et qui est généralement déconseillé).

Reply

Marsh Posté le 11-10-2004 à 20:55:15    

ouais, mais avec le select, ça se complique si t'as un peu de travail à faire avec chaque client.
 
En fait le mieux, c'est un pool de thread :)
 
Tiens quelqu'un connaît une bibliothèque pour faire ça ?
 
 
Sinon les threads sur système unix, ça passe par :
- les POSIX threads
- les Portable Threads (libpth) qui est une très bonne alternative

Reply

Marsh Posté le 11-10-2004 à 21:22:05    

bad11 a écrit :

Coucou !
 
Voila je dois développer un programme perso qui est un serveur qui attend des connections sur le port prédéfini et qui envoie un fichier texte au client qui se connecte , puis déconnecte le client.
Le serveur est fait pour ne jamais s'arreter(boucle infinie) et pour marcher en parallele (traiter plusieurs client en meme tps).
Tres scolaire et tres simple en théorie :).
 
Mon probleme :
 
Je cré un processus fils qui traitera la demande d'un client qui se connecte (avec fork() ).
Mon probleme est que quand je lance mon serveur, chaque processus fils terminé laisse un "zombie" une trace de lui dans la liste des processus.
 
Il faudrait que le programme principal, donc le pere attende la fin du fils qui traite la demande mais là cela ne serait plus un serveur parallele.
 
Comment puis je faire? je développe en C sous Linux.


 
Quand un fils meurt, il reste à l'état de "zombie" tant que son père n'a pas consulté son état. Un des moyens de connaître l'état d'un fils est d'utiliser la primitive "wait".
 
Comment on s'en sert
1) tu déclares dans le père une variable style "int etat"
2) tu appelles dans le père "wait(&etat)"
 
Qu'est-ce qu'il va se passer
Si le fils est encore en vie, ton appel à "wait()" dans le père va bloquer ce dernier jusqu'à ce que le fils se termine.
Dès que le fils meurt (ou s'il est mort avant l'appel à "wait()" ), cet appel est débloqué et la fonction renvoie le pid du fils mort (utile dans le cas de plusieurs fils).
Ensuite, ta variable "etat" contiendra la cause de la mort du fils
- si le fils s'est terminé par "exit(n)", la valeur "n" sera dans le premier octet de la variable "etat" et l'autre octet sera à 0
- si le fils s'est terminé par "kill(n)", la valeur "n" sera placée dans les sept derniers bits de "etat". De plus, le 8° bit sera à "1" si le kill a provoqué la création d'un fichier core.
 
Tu peux utiliser les macros "WIFEXITED()", "WIFSIGNALED()", "WEXITSTATUS()" et "WTERMSIG()" définies dans "sys/wait.h" en y passant ta variable "etat". Ces macros vont tester et/ou extaire de "etat" l'octet qui va bien pour vérifier si la mort a été due à "exit" ou "kill" et récupérer la valeur de "exit" ou de "kill".
 
Le prpblème de "wait" est que c'est bloquant. De plus, tu ne peux pas cibler quel fils tu attends. Cependant, il y a des dérivés de "wait()" comme "waitpid().
Cette primitive est intéressante pour toi car elle permet de cibler quel processus on attend, et elle possède un paramètre "option" dans lequel tu peux y mettre la macro "WNOHANG" (mode non-bloquant) => ton serveur reste parallèle => la fonction renvoie "0" si le fils n'est pas encore fini
 
Si c'est trop compliqué ou trop lourd, tu peux alors utiliser des thread mais ça, je ne sais pas le faire...


Message édité par Sve@r le 11-10-2004 à 21:29:54

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 11-10-2004 à 22:49:25    

je vous remercie je testerai cela demain a l'iut.
 
J'avais testé la fonction waitpid() avec WNOHANG mais j'avais pas réussi a la faire tourner et je n'avais pas insisté car je ne pensais pas etre sur la bonne voie.
 
Je retenterai demain. :)
Merci a tous pour vos conseils : la suite demain soir ! / Thanks Sve@r pour cette bonne explication en français et non remplie de mots barbares linuxiens ^^.


Message édité par bad11 le 11-10-2004 à 22:53:35
Reply

Marsh Posté le 12-10-2004 à 05:36:05    

L'autre moyen de ne pas avoir de zombies, c'est d'écouter SIGCHLD. Tu peux même te contenter de faire un signal(SIGCHLD, SIG_IGN).

Reply

Marsh Posté le 12-10-2004 à 07:56:21    

matafan a écrit :

L'autre moyen de ne pas avoir de zombies, c'est d'écouter SIGCHLD. Tu peux même te contenter de faire un signal(SIGCHLD, SIG_IGN).


Evidemment c'est plus simple...
Cependant il risque d'y avoir un soucis car dans certains systèmes, la fonction "signal" n'est armée qu'une seule fois et se désarme à la réception du signal. dans d'autres systèmes la fonction reste armée pour les autres signaux. A ce que je sais, le comportement dans un cas ou dans l'autre n'est pas encore normalisé.
Si jamais c'est le premier comportement qui est présent sur le système de bad11, alors seul le premier signal du premier fils sera intercepté et les autres resteront zombies.
Un moyen de se prévenir de cet éventuel problème est de positionner le signal(SIGCHLD) sur une fonction qui ne fait que réarmer le signal, du style

Code :
  1. void ignore_fils(int sig)
  2. {
  3.     signal(SIGCHLD, ignore_fils);
  4. }
  5. main()
  6. {
  7.     ...
  8.     ...
  9.     signal(SIGCHLD, ignore_fils);
  10. }


 

bad11 a écrit :

Thanks Sve@r pour cette bonne explication en français et non remplie de mots barbares linuxiens ^^.


Ils sont pas barbares les mots linuxiens :pfff: , tu viens de le dire... ils sont L I N U X I E N S  :p :lol:


Message édité par Sve@r le 12-10-2004 à 07:59:31

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 12-10-2004 à 08:12:07    

Sve@r a écrit :


Code :
  1. void ignore_fils(int sig)
  2. {
  3.     signal(SIGCHLD, ignore_fils);
  4. }



Nope. Même ça ne marche pas bien. Evidemment, si tu as une mort tous les 40 du mois, ça passera, mais pour tout signal reçu plus d'une fois par seconde, tu t'exposes à de jolis problèmes.
 
Il faut utiliser sigaction et ses petits frères.

Reply

Marsh Posté le 12-10-2004 à 20:06:08    

La premiere méthode avec wait et waitpid ne marche pas, rien n'y fait.
 
J'ai testé SigCHD et ca marche , meme avec un tas de connexion.
 
Je vous remercie , a une prochaine fois surement pour un petit coup de pouce :)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed