Département INFormatique 
  CSC4508/M2 : Concepts des systèmes d'exploitation et mise en œuvre sous Unix


    Contenu



Éléments d'architecture client-serveur

(Corrigés)

Exercice 1 : M. et Mme...

Dans cet exercice, on se propose d'écrire un serveur de "M. et Mme" :
  • Le client lit, sur sa ligne de commande, le nom de famille de "M. et Mme". Il l'envoie au serveur.
  • Le serveur cherche ce nom de famille dans le fichier mEtMme.txt :
    • s'il le trouve, il renvoie le nom du fils, de la fille ou bien des enfants
    • sinon il renvoie le message "Désolé, je ne le connais pas"
  • Le client affiche le message reçu du serveur.

Préparation

Se placer dans un répertoire de travail
tar xvfz q1.tgz
cd Q1

Question 1.1

Le code qui vous est fourni dans le répertoire Q1 comprend un client et un serveur qui fonctionnent comme dans l'exemple fourni en cours sur les files de messages :
  1. concernant le client :
    1. il crée une file de message dont le nom est suffixé par son "pid" (de manière à ne pas interférer avec d'autres clients potentiels) ;
    2. il se "connecte" au serveur via la file de messages "/client-serveur" (créée par le serveur) ;
    3. la requête du client contient non seulement le "M. et Mme" cherché, mais aussi le nom de la file de messages a été créée en 1.1 par le client et sur laquelle le client attend la réponse du serveur ;
  2. concernant le serveur :
    1. sur réception d'une requête client, le serveur cherche dans le fichier une ligne qui commence par le "M. et Mme" mentionné dans la requête ;
    2. s'il la trouve, il renvoie l'ensemble de la ligne sur la file de messages mentionnée dans la requête ;
    3. sinon, il renvoie "Desole, je ne le connais pas".
Programmer le serveur de sorte qu'il crée un thread à chaque fois qu'il reçoit une requête. Ce thread traite la requête et disparaît une fois que la requête est traitée.
---beginCorr
serveurQ1.1.corrige.c
---endCorr

Question 1.2

Se positionner dans le répertoire parent de Q1.
Taper la commande : cp  -R  Q1  Q2
Se positionner dans le répertoire Q2 qui vient d'être créé.

Dans ce répertoire Q2 (qui reprend le code de la question Q1), adapter le serveur de sorte qu'il forke 3 threads :
  • Chaque thread ouvre le fichier, se met dans le "pool" de threads en attente et attend une requête du processus distributeur.
  • Sur réception d'une requête, le serveur retire le premier thread du "pool" et lui fait suivre la requête :
    • le thread cherche le "M. et Mme" dans le fichier ;
    • il répond au client ;
    • il se remet dans le "pool" ;
    • il attend une requête du processus distributeur.
Le "pool" de threads peut être implanté à l'aide :
  • d'un tube. Les threads sont en attente de lecture sur ce tube. Quand le serveur veut leur faire suivre une requête, il écrit sur ce tube : l'un des threads lit la requête sur le tube et la traite.
  • d'une file de message (même principe que le tube).
  • d'un tableau circulaire de requêtes géré via le paradigme producteur/consommateur, le serveur étant le producteur et les threads étant les consommateurs.
  • de 4 tubes, 3 tubes serveur-thread (1 par thread) et 1 tube threads-serveur. Quand un thread est prêt à recevoir une requête, il écrit le descripteur de fichier de son tube serveur-thread dans le tube threads-serveur. Il se met ensuite en attente de lecture sur ce tube parent-thread. Quand le serveur reçoit une requête, il lit un descripteur de fichier de tube parent-thread dans le tube threads-parent, puis écrit la requête dans ce tube parent-thread. Le thread lit la requête et la traite.
  • toute solution que vous imaginerez et qui fonctionne !
---beginCorr
Le corrigé implante la solution à base d'un tube (cf. serveurQ1.2.corrige.c).
---endCorr

Question 1.3

Se positionner dans le répertoire parent de Q1.
Taper la commande : cp  -R  Q1  Q3
Se positionner dans le répertoire Q3 qui vient d'être créé.

Dans ce répertoire Q3 (qui reprend le code de la question Q1), programmer le serveur de sorte qu'il forke 26 threads (chacun étant chargé des "M. et Mme" commençant par une certaine lettre de l'alphabet) :
  • Chaque thread cherche, dans le fichier, la première et la dernière ligne commençant par sa lettre.
  • Sur réception d'une requête, le processus distributeur fait suivre la requête à le thread correspondant à la 1-ère lettre du "M. et Mme" :
    • le thread ne cherche que dans les lignes qui le concernent ;
    • il répond au client  ;
    • il attend une nouvelle requête du processus distributeur.
---beginCorr
serveurQ1.3.corrige.c
---endCorr

Question 4 (non corrigée)

Reprendre le code réalisé à la question 1 avec les contraintes suivantes :
  • Le serveur peut forker au maximum 3 threads pour le traitement des requêtes.
  • Chacun de ces threads transmet à un thread spécial (le "factureur") un "ticket de facturation" (contenant le pid du processus demandeur et le nom de M. et Mme demandé). Cet thread spécial écrit ensuite le ticket dans un fichier texte. La transmission d'information entre les threads traitant les requêtes et le "factureur" sera d'abord faite avec un pipe, puis avec une zone de mémoire partagée.
---beginCorr
A compléter
---endCorr

Exercice 2

Repérer les différentes architectures client-serveur mises en oeuvre dans l'exercice 1.
---beginCorr
Dans l'exercice 1 :
  • le code qui est fourni dans le répertoire Q1 utilise une architecture "Serveur mono-tâche".
  • à la question 1, on utilise une architecture "Serveur avec autant de tâches que de clients".
  • à la question 2, on utilise une architecture "Serveur avec autant de tâches que de clients" en limitant à 3 (à l'aide d'un pool de threads) le nombre maximum de tâches à un instant donné. L'avantage de cette architecture par rapport à celle de la question 4 est que les tâches de traitement client ne sont pas créées à chaque requête client.
  • à la question 3, on utilise une architecture "Serveur avec N tâches gérant tous les clients", N étant égal ici à 26.
  • à la question 4, on utilise une architecture "Serveur avec autant de tâches que de clients" en limitant à 3 (à l'aide d'un sémaphore) le nombre maximum de tâches à un instant donné.
---endCorr

Exercice 3 : M. et Mme... mais avec des enfants

Cet exercice reprend les questions de l'exercice 1, mais en utilisant des enfants au lieu de threads.

Préparation

Se placer dans un répertoire de travail
Vérifier que le tar ci-dessous ne risque pas d'écraser l'éventuel travail que vous avez fait sur le répertoire Q1 lors de l'exercice 1.
tar xvfz q1.tgz
cd Q1

Question 3.1

Même fonctionnement qu'à la question 1.1 de l'exercice 1, sauf que dans cette question 3.1, vous devez programmer le serveur de sorte qu'il forke un enfant à chaque fois qu'il reçoit une requête. Cet enfant traite la requête et disparaît une fois que la requête est traitée.
---beginCorr
serveurQ3.1.corrige.c
---endCorr

Question 3.2

Se positionner dans le répertoire parent de Q1.
Taper la commande : cp  -R  Q1  Q2
Se positionner dans le répertoire Q2 qui vient d'être créé.

Même fonctionnement qu'à la question 1.2 de l'exercice 1, sauf que dans cette question 3.2, vous devez travailler avec des processus enfants et pas des threads.

---beginCorr
Le corrigé implante la solution à base de 4 tubes (cf. serveurQ3.2.corrige.c).
---endCorr

Question 1.3

Se positionner dans le répertoire parent de Q1.
Taper la commande : cp  -R  Q1  Q3
Se positionner dans le répertoire Q3 qui vient d'être créé.

Même fonctionnement qu'à la question 1.3 de l'exercice 1, sauf que dans cette question 3.3, vous devez travailler avec des processus enfants et pas des threads.
---beginCorr
serveurQ3.3.corrige.c
---endCorr







Page mise à jour le 17 mai 2016