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 4 bibliothèques et des programmes serveur principal, client d'administration et serveur d'affichage. Chacune de ces entités est développée dans un répertoire propre. On gère donc les 7 répertoires suivants :
Socket -
pour les sources de la bibliothèque contenant les fonctions de gestion des sockets libsck,
Threads -
pour les sources de la bibliothèque contenant les fonctions de gestion des threads libthrd,
IPC -
pour les sources de la bibliothèque contenant les fonctions de gestion des communications inter-processus libipc,
Webcam -
pour les sources de la bibliothèque contenant les fonctions de gestion des webcams libcam,
Demon -
pour le programme du serveur et les modules de traitement des commandes client et administrateur,
Admin -
pour le client d'administration,
Affiche -
pour le serveur d'affichage.
Cette arborescence et quelques squelettes de fichiers sont disponibles sous forme d'un fichier au format tar et compressé à l'URL http://www.plil.net/~rex/Enseignement/Systeme/Tutorat.GIS2.webcam/webcam.tgz. Transférez ce fichier dans votre compte Polytech'Lille et décompressez-le avec la commande tar xvzf webcam.tgz. Le répertoire créé contient déjà un fichier Makefile avec deux cibles all et clean. Créez les Makefile manquants dans les sous-répertoire afin que, lorsque l'on lance make avec ces deux cibles, 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 serveurs

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.c (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 d'affichage

Le problème constaté dans le paragraphe précédent est rédhibitoire pour le serveur principal (serveur de webcams) mais pas pour le serveur d'affichage qui ne doit en fait gèrer qu'un seul client.

Vous allez donc utiliser les fonctions de votre bibliothéque de sockets pour écrire le serveur d'affichage. 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 5000).

Le fonctionnement du serveur d'affichage suit les grandes lignes suivantes : Le serveur d'affichage doit aussi se terminer lorsqu'une touche du clavier est pressée avec la fenêtre d'affichage comme cible.

Un serveur X11 ne peut pas afficher directement les images au format RGB24 (où chaque pixel est défini par 3 octets codant respectivement le rouge, le vert et le bleu). Pour compliquer les choses les serveurs X11 peuvent utiliser une profondeur de 8,16 ou 24 bits par pixel et plusieurs modes d'encodage des couleurs. Nous nous limiterons à l'encodage TrueColor. Dans ce mode les couleurs sont encodées de la façon suivante :
Profondeur 8 bits
: les 3 bits de poids fort codent le rouge, les 3 bits intermédiaires codent le vert et les deux bits de poids faible codent le bleu.
Profondeur 15 bits
: le bit de poids fort est inutilisé et ensuite les couleurs sont codées sur 5 bits.
Profondeur 16 bits
: les 5 bits de poids fort codent le rouge, les 6 bits intermédiaires codent le vert et les 5 bits de poids faible codent le bleu.
Profondeur 24 bits
: chaque couleur est codée sur un octet et un octet supplémentaire code la transparence (donc un pixel nécessite 32 bits).
Attention les octets doivent suivre l'ordre des octets de la machine. En particulier si le processeur est un Intel l'ordre est inversé.

Pour tester votre serveur d'affichage vous pouvez lui envoyer les deux clichés ci-dessous en utilisant la commande nc :
http://www.plil.net/~rex/Enseignement/Systeme/Tutorat.GIS2.webcam/cliche1.rgb24,
http://www.plil.net/~rex/Enseignement/Systeme/Tutorat.GIS2.webcam/cliche2.rgb24.

2.5   Un serveur principal à 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 est le point d'entrée pour la gestion d'un client du serveur de webcam. Vous en avez déjà implanté une première version dans le serveur de test. Vous devrez en écrire une version plus élaborée, pour plus de clareté, ce serait une bonne idée de déplacer cette fonction du fichier serveur.c vers le fichier gestionClient.c.

2.6   Structure de données du serveur

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

2.7   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. En implantant dans le module cdesClient.c les fonctions nécessaires à la gestion des clients et dans le module cdesAdmin.c les fonctions nécessaires à la gestion du client d'administration vous prendrez soin d'y ajouter les poses et levées de verrous nécessaires.

2.8   La gestion des clients

La fonction gestionClient crée une nouvelle entrée dans la table des utilisateurs puis, boucle sur une écoute de la socket de dialogue, en attente d'une requête du client.

Lorsqu'un client souhaite visualiser une caméra, le serveur effectue les tâches suivantes : Bien entendu ces tâches doivent être correctement protégées par des verrous d'exclusion mutuelle. Une difficulté supplémentaire est de ne pas effectuer de conversion d'image superflue. Deux webcams différentes n'enverront pas des images dans le même format (les encodages des couleurs appelés "palettes" peuvent être différents). Il faut donc convertir les images capturées dans un format commun (ici RGB24). Vous prendrez soin de n'effectuer la conversion qu'une seule fois quelque soit le nombre de serveurs d'affichage à alimenter.

Vous devez prévoir un mécanisme pour que l'envoi d'un flux vidéo puisse se terminer sur ordre de l'administrateur. Une solution est de stocker le descripteur de la socket vers le serveur d'affichage dans la table des caméras, de fermer le descripteur à la demande de l'administrateur et de faire en sorte que le thread d'envoi de flux vidéo se termine proprement en cas de problème sur sa connexion vers le serveur d'affichage.

Dans le même ordre d'idée, prévoyez d'arrêter les flux vidéos d'un client lorsqu'il met fin à sa connexion au serveur de webcams.

2.9   Le client d'administration

Il vous faut implanter le client d'administration et le thread chargé de traiter les requêtes de l'administrateur dans le serveur.

Les commandes sont passées en argument au client d'administration (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 client d'administration.

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).

La fonctionnalité la plus complexe à implanter est la configuration d'une caméra. L'administrateur commence par ajouter une caméra dans la table des caméras du serveur (en remplissant juste la structure des paramètres techniques). Le serveur peut tenter à ce moment d'initialiser la webcam pour vérifier son existence et la validité des paramètres fournis. Par la suite l'administrateur va préciser les paramètres administratifs (description et mot de passe). C'est à ce moment que le serveur va lancer un thread pour faire du "streaming" sur la webcam (récupérer constament des images pour que le capteur soit électroniquement opérationnel).

Le thread sera lancé par la fonction lanceThreadCamCapture de la bibliothèque libthrd qui utilise elle-même la fonction gestionCamCapture définie dans le fichier gestionCam.c du répertoire Demon. Pour que ce thread puisse se terminer lorsque l'on supprime une caméra il peut être utile d'ajouter un drapeau d'arrêt dans la structure des caméras définie dans serveur.h.

Lorsque qu'une caméra est supprimée, il ne faut pas seulement arrêter le thread de "streaming" mais aussi tous les threads alimentant des serveurs d'affichage avec des images de cette caméra.
Previous Contents