Le site de DarkOli - Programmation - Redirection
Redirection de l'entrée et de la sortie standard
J'utilise Crafty pour analyser mes parties d'échecs. De plus j'ai besoin d'étudier certaines ouvertures. J'ai donc eu l'idée de développer un programme capable d'interroger automatiquement Crafty. Crafty fonctionne en ligne de commande, une fois le programme lancé il suffit d'entrer les commandes (par exemple : "analyze") ou directement les coups joués ("e4" par exemple) puis crafty affiche un résultat (par exemple le coup qu'il va jouer ou une analyse).
Le programme que je veux créer va devoir écrire sur l'entrée standard de Crafty et lire sa sortie standard !
Je commance par créer deux tubes le premier (A) pour mon programme puisse "envoyer" des commandes à Crafty et le second (B) pour recevoir les réponses de Crafty.
Ensuite je fais un fork() (pour plus d'information : RTFM !). Si aucune erreur ne se produit, j'obtiens donc deux processus : le père (celui qui a fait le fork) et le fils (celui qui vient d'être créé). Les tubes A et B sont connus des deux processus car ils ont été créés avant le fork.
Afin que les choses soient propres, et aussi pour que chaque tube ait un seul écrivain et un seul lecteur, le père ferme le côté lecture du tube A car ce tube va lui serivr à envoyer (écrire) les commandes à Crafty. Le côté écriture du tube B est aussi fermé par le père car ce tube est utilisé uniquement pour recevoir (lire) les résultats de Crafty. Dans le processus fils c'est l'inverse, c'est le côté écriture du tube A qui est fermé ainsi que le côté lecture du tube B !
Enfin l'entrée standard du fils doit être remplacée par le côté lecture du tube A pour cela il faut d'abord fermer l'entrée standard puis dupliquer le côté lecture du tube A ! La fonction dup() utilise le premier descripteur de fichier disponible donc l'entrée standard dans notre exemple. Toute lecture sur l'entrée standard sera en fait une lecture du tube A ! Il faut faire la même opération avec la sortie standard et le côté écriture du tube B.
Une fois que les entrée et sortie standards ont été redirigées il suffit de lancer Crafty à l'aide de la commande execlp() (ou de l'une de ces variantes).
Pour que tout ceci soit masqué pour le développeur j'ai créé une fonction contenant toutes ces manipulations. Ainsi il suffit d'appeler cette fonction en lui donnant deux flux (un pour l'entrée et l'autre pour la sortie) qui seront initialisés respectivement avec le côté écriture du tube A et le côté lecture du tube B à l'aide de la fonction fdopen().
Voici le code C brut ! /******************************************************************************/ /* */ /* Creation d'un processus et redirection des entree et sortie standards. */ /* ========================================================================== */ /* */ /* ? */ /* */ /* -------------------------------------------------------------------------- */ /* */ /* ? */ /* */ /******************************************************************************/ int creer_fils_avec_entree_sortie(char* nom_du_programme, FILE** entree, FILE** sortie) { int tubeA[2]={0,0}; int tubeB[2]={0,0}; pid_t fils=0; /* Contrôle des paramètres */ if (nom_du_programme == NULL) return -1; if (nom_du_programme[0] == '\0') return -1; if (entree == NULL) return -1; if (sortie == NULL) return -1; /* Création du tube A : père => fils */ if (pipe(tubeA) != 0) { fprintf(stderr, "Échec de la création du tube A.\n"); return -1; } /* Création du tube B : fils => père */ if (pipe(tubeB) != 0) { fprintf(stderr, "Échec de la création du tube B.\n"); return -1; } /* Création d'un processus fils */ fils=fork(); if (fils < 0) { fprintf(stderr, "Échec de la création du processus fils.\n"); return -1; } /* Père */ if (fils > 0) { fprintf(stderr, "Création du processus fils Ok : #%d.\n", fils); /* Le côté lecture du tube A est fermé */ close(tubeA[LECTURE]); (*entree)=fdopen(tubeA[ECRITURE], "w"); /* Le côté écriture du tube B est fermé */ close(tubeB[ECRITURE]); (*sortie)=fdopen(tubeB[LECTURE], "r"); /* Fin */ fprintf(stdout, "P : tubes A et B prêts.\n"); } /* Fils */ if (fils == 0) { fprintf(stderr, "F : Préparation du tube B.\n"); /* Le côté lecture du tube B est fermé */ close(tubeB[LECTURE]); /* Fermeture de la sortie standard */ close(STDOUT_FILENO); /* Le côté écriture du tube B devient la sortie standard */ dup(tubeB[ECRITURE]); fprintf(stderr, "F : Préparation du tube A.\n"); /* Le côté écriture du tube A est fermé */ close(tubeA[ECRITURE]); /* Fermeture de l'entrée standard */ close(STDIN_FILENO); /* Le côté lecture du tube A devient l'entrée standard */ dup(tubeA[LECTURE]); fprintf(stderr, "F : Execution du programme dans le processus fils ...\n"); /* Execution du programme */ execlp(nom_du_programme, nom_du_programme, NULL); } /* Fin */ return 0; }
La page respecte le standard XHTML 1.0 Strict.
-- Darkoli, dernière mise à jour le 13 juillet 2006 [00:57] --