Previous Contents

2   Organisation du travail

2.1   Généralités

Il est fortement conseillé de suivre les étapes proposées ci-après pour réaliser le travail.

2.2   Organisation modulaire

Le projet est constitué de 3 bibliothèques et des programmes serveur et gérant. Chacune de ces entités est développée dans un répertoire propre. On gére donc les 5 répertoires suivants :
Socket -
pour les sources permettant de générer une bibliothèque C libsck,
Threads -
pour la bibliothèque libthrd,
IPC -
pour la bibliothèque libipc,
Demon -
pour le programme du serveur et les modules de traitement des commandes client et administrateur,
Admin -
pour le programme d'administration.
Cette arborescence et quelques squelettes de fichiers sont disponible sous forme d'un fichier au format tar et compressé à l'URL http://www.plil.net/~rex/Enseignement/Systeme/Tutorat.GIS4.canaux/canaux.tgz. Transférez ce fichier dans votre compte Polytech'Lille et décompressez-le avec la commande tar xvzf canaux.tgz. Le répertoire créé contient un fichier Makefile qui est incomplet. Notamment, la cible all est vide. Complétez afin que, lorsque l'on lance make, tous les Makefile qui se trouvent dans les différents répertoires soient exécutés.

On prévoira de pouvoir compiler les différents sources avec un drapeau DEBUG (option -DDEBUG de gcc), permettant un affichage conditionnel d'informations de déverminage des programmes.

2.3   Sockets et serveur

Il s'agit dans cette étape de réaliser un serveur TCP basique à l'aide de l'interface de programmation des sockets.

Écrivez dans le module libsck.c (répertoire Socket), les deux fonctions suivantes : Testez cette bibliothèque en écrivant un programme servConf (répertoire Demon) qui l'utilise et dont la fonction de traitement des connexions (celle appelée par boucleServeur) effectue juste une écriture de message dans la socket et clôt la connexion.

Ce programme peut prendre des arguments : -p <port> ou --port <port> pour spécifier un numéro de port différent de celui par défaut (port 4000). Pour traiter les arguments, utilisez la fonction getopt_long (voir la page de manuel correspondante). Si les arguments sont incorrects, on doit afficher un message qui précise la syntaxe. Pour plus de clarté, l'analyse des arguments et l'affichage de la syntaxe seront écrits dans des fonctions séparées.

Modifiez la fonction de traitement des connexions afin que le serveur affiche le nom de la machine distante (sur la sortie standard) et qu'elle ne ferme la connexion que si elle lit le mot-clé quitter sur la socket. Pour ceci, écrivez dans libsck une fonction SocketVersNom qui prend une socket en argument et renvoie le nom dans une chaîne de caractères. Vous utiliserez les fonctions getpeername et gethostbyaddr (voir les pages de manuel et le support du cours de réseau http://www.plil.net/~rex/Enseignement/Reseau/Reseau.GIS2)

Testez votre serveur avec plusieurs telnet ou nc simultanés. Conclusions ?

2.4   Un serveur à base de processus légers

Pour que votre serveur puisse accepter plusieurs clients simultanément, vous allez lancer un processus léger (thread) par client. Pour cela, implémentez la fonction publique de libthrd (répertoire Threads) :

void lanceClientLeger(int) ;
Cette fonction doit avoir comme action de lancer un thread dans le mode détaché. Ce thread doit exécuter la fonction

void gestionClient(int) ; 
Cette dernière, définie dans servConf.c, est le point d'entrée pour la gestion d'un client du serveur de conférences. Elle sera implantée plus tard (sous-section 2.7).

2.5   Structure de données du serveur

Remarque préliminaire : à chaque client connecté est associé un pipe dont l'utilité sera justifiée ultérieurement.

Les principales informations gérées par le serveur sont : Définissez les structures de données correspondantes dans le fichier entête servconf.h et écrivez les fonctions d'initialisation des tables (ne vous préoccupez pas encore des sémaphores).

2.6   Analyse des opérations sur la structure de données

Analysez les opérations nécessaires sur les structures de données afin de déterminer celles qui nécessitent l'utilisation de sémaphores. Implantez dans votre bibliothèque libthrd.a les deux fonctions publiques :

void P(int) ;
void V(int) ;
Ces fonctions cachent totalement le fait que vous utilisez des verrous d'exclusion mutelle pour threads POSIX. En particulier, les verrous sont représentés par une constante. Ajoutez dans le module cdesClient.c, les poses et levées de verrous nécessaires.

2.7   La gestion des clients

La fonction gestionClient crée une nouvelle entrée dans la table des utilisateurs puis, boucle sur une écoute sur la socket de dialogue, en attente d'une requête du client. Lorsque le client s'abonne à un canal, il doit alors recevoir les messages envoyés par d'autres sur ce canal après les avoir éventuellement filtrés (dans le cas où le client a préalablement censuré d'autres utilisateurs). Étant donné que l'on ne souhaite pas mémoriser les messages, un message envoyé sur un canal doit immédiatement être transmis aux abonnés du canal. Si le message est directement écrit sur la socket de dialogue des clients abonnés, il n'est plus possible de filtrer les réceptions de messages. La solution que l'on retiendra consiste à associer un pipe à chaque client connecté. Envoyer un message sur un canal revient alors à écrire le message dans chaque pipe de client abonné. Un client abonné est à l'écoute d'une écriture sur son DP (descripteur de pipe), en règle générale le message doit être écrit sur le DSD (descripteur de socket de dialogue) du client mais si l'expéditeur du message est censuré par le client, l'écriture ne doit pas avoir lieu.

Vous utiliserez la fonction select pour réaliser l'écoute simultanée sur le DP et le DSD (l'écoute sur le DSD est nécessaire car le client peut taper des ordres sur son terminal).

2.8   Le processus gérant

Il ne vous reste plus qu'à implanter le processus gérant et le thread chargé de traiter les requêtes du gérant dans le serveur !

Les commandes sont passées en argument au processus gérant (donc pas d'interface textuelle, mais une analyse des arguments au moyen de getopt_long). Ce processus communique avec le serveur au moyen de 2 files de messages : une pour les commandes et une pour les réponses. La file des commandes est créée par le serveur à l'initialisation. Un thread, lancé par le serveur est chargé de scruter en permanence cette file. La file des réponses est créée par le gérant.

La bibliothèque libipc contiendra toutes les fonctions permettant de cacher le fait que la communication est implantée par IPC (selon le même principe que celui utilisé pour les sémaphores).
Previous Contents