Introduction FAQ TD 1 TD 2 TD 3 TD 4 TD 5 TD 6 TD 7 TD 8
A ce stade du projet, nous allons devoir effectuer une mise à jour complète du projet. Cette tâche est un peu plus compliquée que les mises à jour précédentes. Voici la façon de faire :
tar -zxvf forum.tar.gz
common.c
,
client.c
et server.c
dans le répertoire
contenant les fichiers de l'archive. common_error.c
, client_main.c
et server_main.c
. Si vous avez un doute, vous pouvez
lire ces fichiers pour vérifier que le code que vous supprimez y est
déjà. common.c
, client.c
et
server.c
en fonction des questions demandées. Voici les modifications que vous trouverez dans le nouveau projet:
~/.forum_msgs/
. -x
. f motif
permet de
rechercher un mot motif
dans tous les messages. clean_client
et clean_server
) A la terminaison d'un programme, il peut s'avérer important de
libérer un certain nombre de ressources utilisées par un programme.
Par exemple, dans notre programme actuel, il faut supprimer le fichier
verrou persistant créé par program_lock
, qui empêche
l'exécution d'une autre instance du programme. Il peut aussi être
utile de supprimer certains fichiers temporaires, tels que celui
utilisé pour l'envoi de messages au serveur.
Dans notre cas, nous utilisons respectivement les fonctions
clean_client()
et clean_server()
qui sont
appelées à la terminaison respectivement du client et du serveur.
extern void clean_client(); extern void clean_server();
Redéfinissez ces fonctions dans votre programme pour ne plus
utiliser celles déjà fournies par libforum*.a
. Pour
l'instant, que pouvez-vous libérer comme ressources dans ces fonctions
?
Solutions: clean_client.c , clean_server.c
client_signals
) Sous Unix, un processus doit être prêt à recevoir un certain nombre de signaux de son environnement (SIGQUIT, SIGPIPE, SIGINT, etc...). Si ce n'est pas le cas, il peut se comporter de façon inattendue, en fonction du comportement par défaut de ces signaux.
Dans notre forum, le client utilise une fonction
client_signals()
,
extern void client_signals();
pour spécifier que, à la réception de la plupart des signaux qui tueraient le processus, il faut afficher un message indiquant la réception du signal et terminer proprement en libérant les ressources utilisées.
Testez cette fonction en envoyant divers signaux via la commande
UNIX kill
à votre client.
Voici une liste des signaux que vous pouvez vouloir traiter : SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2.
Fonctions à utiliser (man
): signal
(ou sigaction
, sigemptyset
et sigaddset
).
Solution: client_signals.c
server_signals
) Dans notre forum, le serveur utilise une fonction similaire à
celle du client, server_signals()
,
extern void server_signals();
pour gérer les signaux. Contrairement au client, qui termine
proprement directement à la réception d'un signal, le serveur se
contente de modifier une variable globale sig_end
, que le
serveur teste régulièrement, sachant qu'il doit terminer si cette
variable est différente de zéro.
De plus, le serveur utilise une variable globale
minutes
pour compter le nombre de minutes depuis le
lancement du programme. La valeur de cette variable est utilisée pour
déclencher un remove_expired()
(toutes les minutes), et
la terminaison du serveur (après 30 minutes).
Ecrivez votre fonction server_signals
du serveur,
correspondant à ce comportement. Vous pouvez utiliser la fonction
alarm
pour déclencher un signal toutes les minutes.
Solution: server_signals.c
block_sigchld
et unblock_sigchld
) Une technique très courante consiste à placer une boucle
effectuant des waitpid
dans le récepteur de signaux
SIGCHLD
. Ceci permet d'éviter de laisser des processus
zombie dans le système.
Modifiez la fonction client_signals
précédente pour
utiliser cette technique. Il se peut qu'un seul signal SIGCHLD soit
reçu pour plusieurs processus fils: comment faut-il gérer ce problème
?
Quel risque court maintenant votre programme ? Etudiez en
particulier le code de la fonction call_editor
.
Pour résoudre ce problème, nous avons défini des fonctions
block_sigchld
et unblock_sigchld
qui
permettent de bloquer temporairement la réception des signaux
SIGCHLD:
extern void block_sigchld(); extern void unblock_sigchld();
block_sigchld
bloque le signal SIGCHLD, tandis que
unblock_sigchld
rétablit le comportement précédent de ce
signal.
Modifiez call_editor
pour utiliser ces fonctions et
éviter le risque que la gestion asynchrone des signaux fait courir au
programme.
Définissez maintenant vos propres fonctions
block_sigchld
et unblock_sigchld
. Utilisez
pour cela l'appel système sigprocmask
.