RPC

Projet Systèmes (Master 2009-2010)

L'auteur de cette page est : Jean-Baptiste Yunes

Introduction et généralités

LISEZ JUSQU'AU BOUT!

Il est demandé d'implanter un système d'appel de fonctions inter-processus en utilisant les fonctionnalités vues en cours.

Ce projet devra être:

  1. écrit en langage C,
  2. exécutable le jour de la soutenance sur les machines d'enseignement,
  3. réalisé par groupe d'au plus trois étudiants,
  4. accompagné d'un rapport devant être remis au début de la soutenance.

Il est demandé de constituer les groupes avant la date impérative du 15 décembre 2009, de prévenir l'enseignant chargé du cours et de ne pas en modifier la constitution jusqu'à la soutenance dont la date sera précisée ultérieurement.

La soutenance devra être préparée et chaque membre du groupe devra intervenir.

Description

On désire construire un mécanisme permettant à des applications de faire appel à des procédures appartenants à d'autres applications. On connaît se mécanisme sous le nom de RPC - Remote Procedure Call - Appel de Procédure Distante - qui peut être utilisé dans différents cadres y compris dans un modèle totalement distribué (une application sur une machine X fait un appel à une fonction appartenant à une application qui s'exécute sur une machine Y). Puisque qu'il ne s'agit pas ici de manipuler le réseau on se contentera de recréer un tel mécanisme dans un domaine de communication limité à une seule machine.

Deux modèles sont à envisagéer :

Appel d'une fonction externe

Dans tous les cas (client/serveur ou distribué), un appel à un hypothétique fonction  :
type fonction(type arg, ...)
aura pour prototype :
int appel_externe(const char *fonction, int type, void *retour, ... /* int type, void *arg */, NULL );
ou :
int appel_externe(const char *fonction, struct arg *args,unsigned short nargs);

Où:

fonction
désigne l'identificateur externe (le nom) de la fonction;
struct arg
désigne une structure composée de deux champs
int type
qui correspond à la description d'un type (voir ci-dessous)
void *arg
qui correspond à l'adresse d'un argument ou d'une valeur de retour (voir ci-dessous)
narg
qui correspond au nombre d'éléments du tableau args
type
définit le type C de l'argument qui suit;
retour ou arg
définit l'adresse à laquelle on trouvera en retour de l'appel la valeur de retour de la fonction et à l'appel la valeur des arguments éventuels.

Les différents types supportés sont les suivants:

typetype CCommentaire
TYPE_VOIDvoidne peut apparaître que pour la valeur de retour
TYPE_INTint *
TYPE_STRINGchar *ne peut apparaître comme valeur de retour

Ainsi un appel à une fonction d'addition de deux nombres entiers pourraît prendre la forme suivante:

int i, j , k, r;
// k = j+i;
r = appel_externe("plus",TYPE_INT,&k,TYPE_INT,&j,TYPE_INT,&i,NULL);

La valeur de retour de la fonction appel_externe représente la condition de terminaison de l'appel. On trouvera entre autres:

valeurSémantique
APPEL_OKTout s'est correctement déroulé
FONCTION_INCONNUELa fonction demandée n'est pas disponible
MAUVAIS_ARGUMENTSUn problème avec les arguments a été détecté (type, nombre)
PAS_DE_REPONSELa fonction externe ne répond pas dans le délai imparti (5 secondes)

Mode client/serveur

Comme nous l'avons déjà indiqué un serveur est un processus dédié qui réalise effectivement le calcul d'une (ou plusieurs) fonction(s) particulière(s). Pour cela il reçoit les requêtes de calcul sur un tube nommé qui lui est réservé et, pour chaque requête il peut décider (selon une procédure à définir par vous-même) de réaliser lui-même le calcul (mode synchrone mono-processus), de déléguer le calcul à un processus fils (mode asynchrone multi-processus) ou de réaliser lui-même le calcul par utilisation d'un thread dédié (mode asynchrone mono-processus).

La réponse à une requête donnée est transmise du serveur (ou du procesus dédié correspondant) au client par l'intermédiaire d'un tube nommé créé par le client pour l'occasion. Il faudra donc penser à transmettre le nom de ce tube au serveur pour qu'il soit capable d'envoyer la réponse (on pourra songer au mécanisme consistant à envoyer dans l'entête d'un courrier électronique l'adresse à laquelle il faut répondre...).

Les échanges dans les tubes consistent essentiellement en une sérialisation des valeurs à échanger (voir les détails du format ci-dessous). Tout n'est pas spécifié, en particulier le format global décrivant un appel (à vous de l'inventer).

Mode distribué

Dans ce mode il n'y a pas de serveur! Tout processus peut déclarer publiquement être capable de réaliser un calcul particulier (l'exécution d'une certaine fonction) et tout processus peut demander à ce que soit réalisé un calcul particulier.

Ce mode distribué recquiert toutefois une certaine centralisation. C'est une structure de donnée particulière qui sera centralisé à l'aide d'un segment de mémoire partagée. Ce segment contiendra l'ensemble des informations utiles permettant à un client (processus désirant effectuer un appel de procédure distant - i.e. le client dans le modèle précédent) de retrouver le processus capable d'y répondre et toutes les informations qui lui permettront de lui adresser la demande de calcul en bonne et due forme.

Tout processus qui veut offrir un service de calcul, devra le faire en enregistrant les informations adéquates dans le segment de mémoire partagé. Il devra le faire aussitôt qu'il est prêt à offrir le service. Il prendra soin aussi de supprimer les informations du segment lorsqu'il ne souhaitera plus offrir ledit service.

Dans ce mode, aucun moyen de communication particulier entre les processus n'est spécifié dans ce document. Vous êtes donc libre d'imaginer ce que bon vous semble. Vous remarquerez aussi que rien n'est dit quand à la synchronicité des appels et des problèmes de concurence; choisissez un mode de fonctionnement raisonnable (i.e. qui préserve une certaine consistance à trouver vous-même.

La sérialisation

Le format des sérialisations de certains types vous est imposé :

typecodageExemple
TYPE_VOID0x00
TYPE_INT0x01, suivi par la longueur du tableau de caractère qui suit codée sur 1 octet, tableau représentant le codage alphanumérique décimal de l'entierL'entier 123 est sérialisé en: 0x01, 0x03, '1', '2', '3'
TYPE_STRING0x02, suivi par la longueur du tableau de caractère qui suit codée sur 1 octet, tableau représentant la chaîne (caractère nul non compris!)La chaîne "abc" est sérialisé en: 0x02, 0x03, 'a', 'b', 'c'

La réalisation

Comme d'habitude il est recommandé de procéder avec précaution; et surtout de commencer par réfléchir. Les choix sont nombreux et notamment en ce qui concerne la communication entre les divers processus. Les divers protocoles ne sont pas fixés seul le format de sérialisation des données l'est, vous devez donc définir les divers protocoles et les formats manquants; ainsi que différents mode de fonctionnement dynamiques (réactions aux signaux, ou autres plaisirs de ce type). Le rapport devra, en particulier, détailler tout cela.

Il est obligatoire de réaliser la communication en mode client/serveur synchrone mono-processus pour capter l'attention des enseignants lors de la soutenance. Attention, il s'agit d'un minimum! Vous êtes encouragés à aller bien plus loin. La cerise sur le gâteau (pour les gourmands) serait d'aller jusqu'à la réalisation fonctionnelle du mode distribué.

Vous serez amenés à réaliser par vous-même différents tests pour vous convaincre que votre réalisation fonctionne. S'il vous plaît, munissez-vous de ces tests lors de la soutenance puisqu'il faudra convaincre les enseignants que cela fonctionne! Même les tests négatifs peuvent être parfois intéressants.

Vous disposez de divers moyens de conserver des versions, servez-vous en, et ne venez pas à la soutenance en ayant effectué une modification apparemment anodine et dont l'impact se révèle finalement désastreux tout en déclarant « mais ça marchait tout à l'heure »! Si « ça marchait », alors c'est qu'il vous était possible de venir avec quelque chose qui marchait. Les prototypes, qui eux ont droit à l'erreur, ne seront examinés qu'à la fin! Bref, montrez ce que vous savez faire, puis montrez ce que vous auriez pu ou voulu faire, ensuite...

On prendra soin d'être modulaire! L'aspect « génie logiciel » ne doit jamais être négligé (les enseignants en tiendront compte).

Les enseignants sont normalement à votre disposition pour vous aider, y compris à démarrer! Ne restez pas bloqués avec entêtement sur un point, demandez de l'aide, et en priorité aux enseignants!

ATTENDEZ UNE JOURNÉE, PUIS RELISEZ UNE SECONDE FOIS JUSQU'AU BOUT AVANT DE SAUTER AVIDEMENT SUR VOTRE CLAVIER!