Previous Contents Next

2   Organisation du travail

2.1   Généralités

Afin de faciliter votre travail, 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 2 bibliothèques et du programme serveur. Chacune de ces entités est développée dans un répertoire propre. On gère donc les 3 répertoires suivants :

Socket -
pour les sources permettant de générer une bibliothèque C libsck,
Threads -
pour la bibliothèque libthrd,
Demon -
pour le programme du serveur et les modules de traitement des commandes client et la gestion des ventes.
Cette arborescence et les sources sont disponible sous forme d'un fichier au format tar et compressé à l'URL http://www.plil.net/~rex/Enseignement/Systeme/Tutorat.IMA2i.encheres/encheres.tgz. Transférez ce fichier dans votre compte Polytech'Lille et décompressez-le avec la commande tar xvzf encheres.tgz. Le répertoire créé contient un fichier Makefile qui est incomplet. Notamment, la cible all et la variable DIRS sont vides. 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 serveur (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.IMA2i)

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 ventes. Elle sera implantée plus tard (sous-section 2.7).

2.5   Structure de données du serveur

Les principales informations gérées par le serveur sont : É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 gestionClient.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 met un produit en vente, une nouvelle entrée dans la table des produits est créée ; le produit ainsi ajouté est dans un premier temps invalide. Le thread ``client'' doit alors lancer un thread ``vente'', chargé de gérer les enchères pour ce produit. Le produit ne deviendra valide que lorsque le thread vente aura été lancé. Pour cela, implémentez la fonction publique de libthrd (répertoire Threads) :

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

void gestionVente(int) ; 
Cette dernière, définie dans serveur.c, est le point d'entrée pour la gestion d'une vente d'un produit.

Lorsque le client propose une enchère pour un produit, le thread client vérifie la validité de l'enchère et l'écrit sur le tube du thread vente correspondant.

2.8   La gestion des ventes

Un thread ``vente'' gère les enchères pour un produit, la diffusion des messages d'alerte et adjuge la vente. Il doit donc gérer un minuteur (timeout) entre deux enchères successives. Les enchères effectuées par un client sont lues par le thread ``vente'' sur le tube qui lui est associé. Pour permettre une attente sur le tube avec minuteur, on utilisera la fonction select (voir la page de manuel). Si le minuteur expire entre deux enchères, le thread ``vente'' diffuse alors à l'ensemble des clients participant à la vente, un message d'alerte (1 fois, 2 fois, 3 fois) ou un message "adjugé". Lorsqu'une vente est adjugée, le produit est supprimé de la table des produits.


Previous Contents Next