Exercice 1 : Programmation modulaire
Transcription
Exercice 1 : Programmation modulaire
Magistère STIC Module Programmation 2 Examen du 7 avril 2005 2004–2005 Le devoir est à rendre par e-mail à [email protected] au plus tard le lundi 11 avril à 12h00, sous la forme d’un archive tar contenant – en trois répertoires différents le code pour résoudre les trois parties du devoir, avec un Makefile correct pour les compiler et exécuter vos tests ; – un bref document expliquant vos choix et les éventuels problèmes rencontrés, et détaillant la structure de la modélisation objet pour l’exercice 2. Exercice 1 : Programmation modulaire Une pile de protocoles est usuellement représentée dans les livres de texte comme suit : ··· TCP IP Ethernet où chaque protocole peut appeler le protocole immédiatement inférieur pour demander l’exécution de fonctions de niveau inférieur. Le but de ces deux exercices est de vous faire réaliser une pile de protocoles composables très simplifiée selon l’approche modulaire et selon l’approche orienté objet. Protocoles comme foncteurs Nous nous fixons la signature suivante, où un message est représenté comme une suite d’entiers (une simplification d’un paquet réseau). module sig type type val val val val end type PROTOCOL = connection message = int list int_of_connection : connection -> int connect : (message -> unit) -> connection send : connection -> message -> unit c_close: connection -> unit Quelques explications. Les valeur du type connection retournés par connect sont des identifiants de connexion, utilisés pour envoyer des messages sur une connexion (opération send), et pour fermer une connexion (opération close). Il n’y a pas de fonction receive : la fonction connect prend en effet en paramètre une fonction de type message->unit qui sera appelée par la pile de protocole chaque fois qu’un message arrive sur la connexion ouverte ; on appelle ce genre de fonctions des callback. 1 Dans notre modèle très simplifié, on n’introduira pas d’adresses ou ports : nous évitons de modéliser le mécanisme complexe nécessaire pour établir des communications point à point entre deux parties, en décidant qu’une connexion revient à un canal de communication partagé entre toutes les parties qui exécutent l’opération connect. Chaque opération send effectuera en pratique un broadcast de son message qui sera traité par tous les callbacks actifs, sauf celui de la connexion qui a envoyé le message. Enfin, int of connection rend un entier unique qui distingue une connexion de toutes les autres. Exercice 1.1 Réalisez un foncteur Ether (X : sig end) : PROTOCOL qui réalise la couche basse de la pile de protocole. Chaque module produit en appliquant Ether à (struct end)devra effectuer les tâches suivantes : – garder la liste des connexion actives, – passer chaque message reçu à toutes les fonctions qui ont été enregistrées par les opérations connect précédentes, sauf celle qui a envoyé le message. Par exemple, la séquence module Ethernet = Ether (struct end);; let handler l = List.iter (Printf.printf "%d - ") l; print_newline();; let c1 = Ethernet.connect handler;; Ethernet.send c1 [32];; ne produira rien, le message est perdu. let handler l = List.iter let c1 = Ethernet.connect let c2 = Ethernet.connect let c3 = Ethernet.connect Ethernet.send c1 [32];; (Printf.printf "%d - ") l; print_newline();; handler;; handler;; handler;; produira deux impressions, une effectuée par le callback de la connexion c2 et une effectuée par le callback de la connexion c3 32 32 - Exercice 1.2 Réalisez un foncteur Noduplicates (Lower :PROTOCOL) : PROTOCOL qui garantie qu’un même paquet ne sera jamais traité deux fois, en jetant tous les duplicata. Pour faire cela, la fonction send de cette couche ajoutera dans le paquet une étiquette unique pour chaque paquet. Exercice 1.3 Réalisez un foncteur Checksum (Lower :PROTOCOL) : PROTOCOL qui garantie l’intégrité des données d’un paquet, en ajoutant un checksum en tête du paquet au moment de l’envoi, et le vérifie à la réception. 2 Exercice 1.4 Modifiez votre module Ether de façon que une fois sur deux il duplique le paquet et une fois sur trois modifie un des entiers le composant, puis testez votre pile de protocoles, en utilisant au moins le code suivant module T1 = Ether(struct end) let c1 = T1.connect handler let c2 = T1.connect handler for i = 0 to 15 do T1.send c1 [i] done module T2 = Checksum(Ether(struct end)) let c1 = T2.connect handler let c2 = T2.connect handler for i = 0 to 15 do T2.send c1 [i] done module T3 = Noduplicates(Checksum(Ether(struct end))) let c1 = T3.connect handler let c2 = T3.connect handler for i = 0 to 15 do T3.send c1 [i] done Exercice 2 : Protocoles orientés objets Proposez une modélisation de la même pile modulaire de protocoles en utilisant des classes et des objets, et en réalisant les mêmes tests. Exercice 3 : Programmation parallèle Écrivez un programme OCaml sieve.ml, en utilisant la librairie Unix, qui lit un entier n en entrée, et puis produit les premiers n nombres premiers par la méthode du crible d’Eratosthene, implémentée en parallèle, selon le schéma suivant : 1. avec n opérations fork successives, on construit n processus, tels que le processus i est relié a i+1 par un canal en écriture, et à i-1 par un canal en lecture 2. le processus 0 (le père) imprime 1 et envoyé au processus 1 les entiers à partir de 2 3. le processus i (> 0) lit le premier entier provenant de i-1, l’imprime et le mémorise dans une variable premier, puis lit tous les autres entiers, jette les multiples de premier et envoie les autres au processus i+1 Modifiez ensuite votre programme de la sorte que, une fois le n-ème nombre premier imprimé, les n processus terminent sans erreur. 3