Introduction FAQ TD 1 TD 2 TD 3 TD 4 TD 5 TD 6 TD 7 TD 8
Récupérez l'archive forum.tar.gz
La version actuelle de forum.tar.gz
est celle
du mardi 17 janvier 2007, 10h50.
La plupart des modifications que nous faisons sont dans les
fichiers libforum*.a
. Pour bénéficier de ces
modifications, vous devez simplement extraire l'archive dans un autre
répertoire, et déplacer les fichiers dans votre propre répertoire,
avant de recompiler votre projet:
mkdir tmp_forum cd tmp_forum tar -zvxf ~/forum.tar.gz # extraire l'archive dans un repertoire temporaire mv libforum*.a ~/mon_forum/ # deplacer les librairies dans votre projet cd .. rm -rf tmp_forum # effacer le repertoire temporaire cd ~/mon_forum/ make # recompiler
Pour des raisons peu claires, le programme ./client
s'exécute difficilement dans les terminaux par défaut
(Kconsole
). Nous vous conseillons donc de lancer un autre
type de terminal pour tester le client:
xterm &
Dernières modifications:
Cette archive contient un certain nombre de fichiers sources
(*.c
et *.h
), un Makefile
(spécifiant les dépendances entre les fichiers) et deux librairies
déjà compilées (libforum*.a
). Le but des TD est d'écrire
des fonctions remplaçant progressivement celles contenues dans ces
librairies.
Pour compiler le projet sur vos machines, vous devez d'abord extraire le contenu de l'archive:
tar -zxvf forum.tar.gz
A chaque fois que vous voulez compiler, il suffit de faire (dans forum/
):
make
qui utilise le fichier Makefile
pour compiler dans le bon
ordre tous les fichiers:
gcc -Wall -g -c -o common.o common.c gcc -Wall -g -c -o client.o client.c gcc -Wall -g -o client common.o client.o libforumclient.a gcc -Wall -g -c -o server.o server.c gcc -Wall -g -o server common.o server.o libforumserver.a
On pourra tester ensuite en lançant le serveur:
./server
puis le client intéractif:
./client
Finalement, utiliser la touche q
pour terminer le
client, et pour le serveur, la commande:
killall server
program_lock
et program_unlock
)
Le client et le serveur font appel aux fonctions
program_lock()
et program_unlock()
,
prototypées et documentées dans common.h
, et définies
dans common.c
. La première vérifie que le programme qui
vient d'être lancé (client ou serveur) n'est pas déjà en train de
s'exécuter, en testant la non-existence d'un certain fichier. La
deuxième est exécutée à la terminaison du programme, pour supprimer ce
fichier, et permettre la prochaine exécution du programme.
Implémentez ces fonctions dans common.c
, à l'aide des
fonctions de bibliothèque fopen()
, fclose()
,
getenv()
et unlink()
.
program_lock.c et program_unlock.c
La documentation est placée dans des pages de manuel, accessibles
par la commande man
:
man fopen
Si la documentation que vous obtenez n'est pas celle que vous cherchez, il se peut qu'une autre fonction du même nom existe, il faut alors spécifier la section du manuel que vous désirez lire:
man 3 fopen
Les commandes Unix (du shell) se trouvent dans la section 1, tandis que les fonctions que vous utiliserez dans ce cours sont dans les sections 2 (appels systèmes) et 3 (bibliothèques).
D'une manière générale, il est plus facile de lire les manuels
et messages en anglais, car les pages françaises sont souvent
partielles et mal traduites. Pour cela, placer la variable
d'environnement LANG
à la valeur C
ou en
:
setenv LANG C
read_line
)
La fonction read_line()
est prototypée dans
common.h
et définie dans common.c
:
extern int read_line (FILE *fp, char *line, int maxlen);
Elle est utilisée par le client et le serveur pour lire une chaîne de
caractéres dans un fichier. L'argument fp
désigne ce
fichier et line
est un tampon
d'au moins maxlen
octets. La lecture s'arrête dès lors
que l'un des trois cas suivants est rencontré :
La chaîne est complétée par un caractère \n
(retour à la ligne) est lu ;
EOF
ou
feof()
) ;
maxlen-1
caractères ont été lus.
\0
, et la
fonction retourne le nombre de caractères effectivement lus.
Cette fonction est actuellement implantée
libforumclient.a
pour permettre de tester le système
complet. Vous devez implanter votre propre fonction
read_line
dans common.c
, en supprimant les
commentaires qui l'entourent.
core
. Que faire ?
Le core est une copie de la mémoire du processus, faîte au moment de l'erreur. Cette copie vous permet de retrouver à quel moment et dans quelles conditions l'erreur s'est produite. Pour que cette empreinte soit produite, il peut être nécessaire de modifier l'environnement:
limit coredumpsize 150M
Pour cela, utilisez le devermineur gdb
. Si votre
programme est ./client
et le fichier mémoire généré
s'appelle core
, tappez:
gdb ./client core
Pour examiner à quel moment l'erreur s'est produite, tappez
simplementbt
dans gdb
:
gdb> bt
qui devrait afficher l'enchaînement des appels de fonctions au moment de l'erreur.
write_rc
)
Le fichier ~/.forum
, appelé fichier de
configuration du client, sert à mémoriser les articles déjà lus
lors des exécutions précédentes du client par un utilisateur donné.
Le client maintient une liste doublement chaînée cyclique d'intervalles, définie de la manière suivante :
struct interval { int beg; int end; struct interval *next; struct interval *prev; };Chaque intervalle désigne des numéros consécutifs d'articles déjà lus. Le champ
prev
de la tête et le champ
next
de la queue pointent respectivement sur la queue et
la tête de la liste. La liste est supposée triée en permanence et les
intervalles disjoints. L'intervalle [-1;-1] correspond à l'intervalle
vide.
La fonction write_rc()
est prototypée dans
client.h
et définie dans client.c
:
extern void write_rc (char *filename, struct interval* intervals);
L'argument filename
est le nom du fichier dans lequel écrire les
intervalles d'articles lus et l'argument intervals
est
la liste d'intervalles.
Une fonction write_rc
est déjà fournie dans
libforumclient.a
pour cette tâche. Ré-implantez cette
fonction, en respectant le format décrit par l'exemple suivant :
la liste formée de l'article 17 (intervalle 17 à 17) puis de
l'intervalle 41 à 43 puis de l'intervalle 2000 à 2007 sera écrite sous
la forme :
17 41-43 2000-2007Le nombre et la nature des espaces (blanc, tabulation ou retour à la ligne) n'importe pas entre les intervalles (tant qu'il y en a au moins 1), mais les espaces sont interdits entre les numéros d'articles et les tirets.
read_rc
)
La fonction read_rc()
est prototypée dans
client.h
et définie dans client.c
:
extern struct interval* read_rc (char *filename);
L'argument filename
est le nom du fichier depuis lequel les
intervalles d'articles sont lus ; la fonction retourne une liste
d'intervalles. La fonction doit également vérifier que la liste ainsi
construite ne comporte que des intervalles disjoints et que ceux-ci
sont triés. Si ce n'est pas le cas, ou que le format n'est pas
respecté (voir question précédente), la fonction appelle
exit_with_error
en indiquant que le fichier de
configuration est corrompu.
Une fonction read_rc
est déjà fournie dans
libforumclient.a
pour cette tâche. Ré-implantez cette
fonction. Vous aurez intérêt à utiliser les fonctions
isdigit()
et isspace
et à construire
l'automate fini correspondant à l'analyse lexicale du fichier de
configuration.
safe_mkdir
) Le serveur stocke l'ensemble des articles dans un répertoire de
votre machine (/tmp/forum
si vous n'utilisez pas
l'argument -d
). Si ce répertoire n'existe pas, le serveur
le crée au démarrage.
Pour cela, le serveur appelle la fonction safe_mkdir()
:
extern void safe_mkdir(char *directory);
Elle est définie dans le fichier server.c
. Cette
fonction ne gère pas certains cas, en particulier la possibilité que
l'un des répertoires pères n'existent pas non plus (testez avec
./server -d /tmp/dir1/dir2/forum
).
Modifiez la fonction safe_mkdir()
pour supporter
cette possibilité, en créant au besoin les répertoires pères.
Nouvelle fonction à utiliser: mkdir
, et
optionnellement l'appel système access
pour simplifier le
test d'existence d'un fichier (d'un répertoire en l'occurence).