THIEFFRY Joël (minfg120@cict.fr)

le 10-05-2002 à

Logo de l'UPS

Rapport du mini-projet sur les Sockets:

"Serveur de sémaphores"





 

Préambule

Je, sousigné Joël THIEFFRY, ai intégralement réalisé les serveurs et clients demandés dans le sujet proposé. "minfg120" est le login que m'ont donné les administateurs du CICT. "IoDream" est un de mes pseudonymes, celui que j'utilise sur les diverses mailing-list auxquelles je participe.
Les fichiers de ce projet sont placés dans la domaine public, à l'exception de j_net.c et j_net.h qui font partie du projet j_net (que je n'ai pas encore officiellement publié) placé sous la licence Lesser Gnu Public Licence (ou LGPL).
Je ne saurais être tenu pour responsable des éventuels disfonctionnements dûs à une utilisation, bonne ou mauvaise, d'un de ces programmes.


 

Table des matières

  1. But du projet
  2. Liste des fichiers fournis
  3. Mise en route
  4. Protocole utilisé
    1. Primitives de dialogue
    2. Organisation générale
    3. Dialogue
      1. Cas sans blocage
      2. Cas avec blocage
  5. Programmation d'un client
  6. Conclusion

  1. But du projet


  2. Liste des fichiers fournis
  3. Nom du fichier Description
    Fichiers du projet
    demo.sh Script shell de démonstation du serveur et du client.
    j_net.c Code source de la librairie utilisée pour les sockets.
    j_net.h Interface de la librairie utilisée pour les sockets.
    Makefile Fichier utilisé par make pour compiler automatiquement les sources du projet.
    sem_client.c Code source du client.
    sem_config.h Interface où sont définies les constantes d'usage général.
    sem_debug.h Interface définissant une macro-fonction d'aide au débogage.
    sem_gen.c Code source d'une librairie contenant des fonctions génériques pour le serveur.
    sem_gen.h Interface d'une librairie contenant des fonctions génériques pour le serveur.
    sem_gest.c Code source de la fonction de gestion des sémaphores du serveur de sémaphores.
    sem_interface.c Code source des fonctions pour interfacer le client avec le serveur.
    sem_interface.h Interface des fonctions pour interfacer le client avec le serveur.
    sem_server.c Code source du serveur.
    sem_server.h Interface du serveur.
    sem_sock_serv.c Code source du serveur de sockets pour le serveur de sémaphores.
    Fichiers d'intérêt général en rapport avec le projet
    Copying Version en anglais de la GNU LGPL.
    Licence Publique Générale GNU Limitée.html Version en français de la GNU LGPL.
    Licence Publique Générale GNU.html Version en français de la GNU GPL.
    Logo_UPS.gif Logo de l'Université Paul Sabatier, Toulouse III.
    Fonc_Diag.gif Image du diagramme de fonctionnenment du serveur. Utilisé dans le rapport.
    Rapport_minfg120.html Le rapport que vous êtes en train de lire.
    Sujet_ProjetSockets.html Sujet de ce projet, récupéré du site Internet du professeur.


  4. Mise en route


  5. Protocole utilisé
    1. Primitives de dialogue
    2. Primitive Description
      Requêtes du client
      CREATE id Création du sémaphore d'identificateur id.
      DESTROY id Destruction du sémaphore d'identificateur id.
      WAIT id Attente sur le sémaphore d'identificateur id.
      RELEASE id Signalement du sémaphore d'identificateur id.
      RESET Réinitialisation du serveur de sémaphores.
      Réponses du serveur
      OK Primitive exécutée avec succés.
      ERROR: semaphore already created Erreur: vous avez essayé de recréer le sémaphore d'identificateur id qui a déjà été crée.
      ERROR: semaphore not created yet Erreur: vous avez essayé de détruire le sémaphore d'identificateur id qui n'a pas encore été crée.
      ERROR: semaphore id out of range (max is xx) Erreur: l'intervalle valide des identificateurs de sémaphore est compris entre 1 et xx.
      Note: toutes les primitives se terminent par un retour chariot ("\n" en C) non représenté ici.

      J'ai essayé de garder les primitives aussi simples que possible. De ce fait, toutes les requêtes du client sont composées d'un mot en majuscules éventuellement suivi d'un identificateur numérique. Pour les réponses du serveur, soit c'est bon ("OK"), soit il y a une erreur ("ERROR: ") qui est suivie d'une phrase expliquant le problème.

    3. Organisation générale
    4. Diagramme de fonctionnement
      J'ai tout fait pour rendre indépendants les différents composants du serveur. Lors du lancement du serveur, celui-ci se découpe en deux processus: le serveur de sockets et le gestionnaire de sémaphores.
      Le serveur de socket est l'interface de communication du serveur. Il attends une connexion d'un éventuel client, puis crée un processus pour permettre le dialogue. Ce processus récupère la requête du client et l'envoie très peu modifiée au gestionnaire de sémaphores. Il récupère la réponse du gestionnaire, créant éventuellement une attente pour le client (cas du WAIT bloquant), puis renvoie la réponse au client.
      Le gestionnaire de sémaphores est le cœur du traitement des opérations sur les sémaphores. Il récupère toutes les requêtes transmises par le serveur de sockets, les traite, et renvoie le résultat à ce même serveur de sockets.
      Le principe de base de ce serveur est que le gestionnaire doit rester unique, mais comme les requêtes des clients peuvent s'autobloquer, c'est la partie serveur de socket qui se dédouble pour pouvoir prendre ne compte toutes le requêtes sans que l'accès au gestionnaire de sémaphores soit bloqué.
      Pour la communication intra-serveur, il existe deux tubes, nommés pipePS2GE et pipeGE2PS, qui permettent le transfert de messages respectivement des processus du serveur de sockets (PS) au gestionnaire de sémaphores (GE), et inversément. Comme le nombre de processus du serveur de sockets est plus grand que un, il a fallu crée un mutex, nommé simplement mutex, entre les deux composants du serveur, géré de manière intelligente pour éviter l'interbloquage. C'est que que nous verrons au chapitre dialogue.

    5. Dialogue
    6. Il existe deux types de dialogue: sans blocage, et avec blocage (cas du WAIT sur un sémaphore bloqué). Nous allons voir ces deux cas dans les deux diagrammes suivants qui montrent l'évolution du dialogue au cours du temps.

      1. Cas sans blocage
      2. Client Processus du Serveur de Sockets Gestionnaire de Sémaphores
        "Requête" |----------socket----------> 
         lock_mutex 
         "Requête" |---------pipePS2GE--------->
         <---------pipePS2GE---------| "Réponse"
         unlock_mutex 
        "Réponse" <----------socket----------| 

        C'est comme ceci que se déroulent la plus grande partie du cheminement des requêtes. Même pour le "WAIT" non bloquant.
        Note: dans la cas du RESET, il n'y a pas de confirmation du gestionnaire de sémaphores, donc ce gestionnaire ne renvoie pas de réponse. De ce fait, le Processus du Serveur de Sockets renvoie de lui-même la réponse "OK" au client.

      3. Cas avec blocage
      4. Client Processus du Serveur de Sockets Gestionnaire de Sémaphores
        "WAIT id" |----------socket----------> 
         lock_mutex 
         "WAIT id pid" |---------pipePS2GE--------->
         <---------pipePS2GE---------| "WAIT"
         unlock_mutex 
        attente du déblocage du sémaphore id
         lock_mutex 
         <---------pipePS2GE---------| "OK"
         <--/\/\/\--SIGUSR1--/\/\/\--|        
         unlock_mutex 
        "Réponse" <----------socket----------| "OK" 

        Le Processus du Serveur de Sockets bloque le client tant que le sémaphore id n'a pas été signalé pour lui.
        Comme les lignes de communications internes (les tubes) sont partagés entre tous les Processus du Serveur de Sockets, il faut indiquer au bon processus que c'est à lui de prendre la communication. C'est le rôre du signal SIGUSR1.


  6. Programmation d'un client
  7. Pour faciliter la programmation des clients, j'ai choisi de créer une "interface" en langage C regroupant les fonctions utiles pour dialoguer avec le serveur. Vous pouvez en voir un aperçu dans le fichier
    sem_interface.h.
    Il existe trois manières d'envoyer les messages au serveur: une en construisant une chaî de caractères, une en utilisant un paramètre de type enum sem_request (que l'on peut retrouver en haut de sem_gen.h). Pour compiler votre client à l'aide de cette interface, il vous suffit d'ajouter #include "sem_interface.h" en haut de votre code source, puis de compiler en incluant j_net.o sem_interface.o et sem_gen.o dans les objets compilés (ex: gcc -o client client.o j_net.o sem_interface.o sem_gen.o).


  8. Conclusion
  9. Pour réaliser ce mini-projet, j'ai tout d'abord dessiné sur papier les diagrammes d'architecture et de dialogues qui n'ont pas changé durant le reste du projet. J'ai choisi de baser tout le logiciel sur projet j_net qui est une librairie facilitant l'utilisation des sockets, réalisée à la base pour la conception d'un serveur HTTP non fini à ce jour.
    Le codage en lui-même a duré environ 12h réparties sur 5 jours. Suivent 3 jours de test/débogage sous WindowsXP (sous Cygwin 1.3.6-1, environnement de travail principal) et Linux Mandrake 7.2 .
    Le plus long fut sans conteste l'écriture de la démonstration et surtout du rapport, qui se sont étalés sur 3 semaines. La cause de cette latence est le manque d'habitude pour réaliser une documentation, aidée par la difficulté à faire le choix entre les différentes technologies (entre Word, RTF, HTML, LaTeX, ...). Finalement j'ai choisi le code HTML pour sans grande portabilité (plus que Word et RTF), et sa facilité de mise ne œuvre (plus simple que LaTex), tout en générant un résultat acceptable aussi bien en consultation qu'en impression.



Créé le 10-05-2002 à Toulouse, France par THIEFFRY Joël (
minfg120@cict.fr)