Systèmes d'exploitation et programmation système Yves PAGNOTTE Chapitre 13 1 /
Systèmes d'exploitation et programmation système Yves PAGNOTTE Chapitre 13 1 / 8 Chapitre 13 Chapitre 13 Chapitre 13 Chapitre 13 LES TUBES LES TUBES LES TUBES LES TUBES Nous avons vu dans les chapitres précédents deux moyens pour faire communiquer des processus sous UNIX : les signaux et les sémaphores. Les sémaphores, ainsi que les tubes, les files de messages et les segments de mémoire partagée constituent les IPC (Inter Process Communications), apparus avec UNIX System V. Le fichier /usr/include/sys/ipc.h contient la définition des objets et des noms symboliques utilisés par les primitives des IPC. Qu'il s'agisse des sémaphores, des tubes, des files de messages ou des segments de mémoire partagée, il s'agit d'objets externes au SGF. Pour chacune de ces catégories, il existe une primitive (....get) d'ouverture/création (cf. ouverture des fichiers). Elle donne au processus une identification de l'objet interne (cf. descripteurs de fichiers). 1. DEFINITION ET CARACTERISTIQUES 1. DEFINITION ET CARACTERISTIQUES 1. DEFINITION ET CARACTERISTIQUES 1. DEFINITION ET CARACTERISTIQUES Les tubes (pipes) constituent le mécanisme fondamental de communication entre processus sous UNIX. Ce sont des files d'octets. Il est conseillé de les utiliser de façon unidirectionnelle. Si l'on veut une communication bidirectionnelle entre deux processus, il faut ouvrir deux tubes, chacun étant utilisé dans un sens. Un tube est implémenté de façon proche d'un fichier : il possède un i- node, mais ne possède pas de nom dans le système ; son compteur de liens est nul puisque aucun répertoire n'a de lien avec lui. Les tubes sont accessibles au niveau du shell pour rediriger la sortie d'une commande sur l'entrée d'une autre (symbole | ). Comme un tube ne possède pas de nom, il n'existe que le temps de l'exécution du processus qui le crée. Plusieurs processus peuvent lire ou écrire dans un même tube, sans qu'on puisse différencier l'origine des informations en sortie. La capacité d'un tube est limitée (PIPE_BUF octets). Les processus communiquant par un tube doivent avoir un lien de parenté (par exemple descendance d'un ancêtre commun ayant créé ce tube : problème classique de l'héritage des descripteurs de fichiers par un fils). 2. CREATION 2. CREATION 2. CREATION 2. CREATION ET UTILISATION D'UN TUBE ET UTILISATION D'UN TUBE ET UTILISATION D'UN TUBE ET UTILISATION D'UN TUBE La création d'un tube correspond à celle de deux descripteurs de fichiers, l'un permettant d'écrire dans le tube et l'autre d'y lire par les opérations classiques read et write de lecture/écriture dans un fichier. Pour cela, on utilise la fonction prototypée par : int pipe (int *p_desc) où p_desc[0] désigne le n° du descripteur par lequel on lit dans le tube et p_desc [1] désigne le n° du descripteur par lequel on écrit dans le tube. La fonction retourne 0 si la création s'est bien passée et - 1 sinon. La fonction C prototypée par : FILE * fdopen (int desc, char *mode) Systèmes d'exploitation et programmation système Yves PAGNOTTE Chapitre 13 2 / 8 permet d'associer un pointeur sur FILE au tube ouvert ; mode doit être conforme à l'ouverture déjà réalisée. 3. SECURITES APPORTEES PAR UNIX 3. SECURITES APPORTEES PAR UNIX 3. SECURITES APPORTEES PAR UNIX 3. SECURITES APPORTEES PAR UNIX Un processus peut fermer un tube, mais alors il ne pourra plus le rouvrir. Lorsque tous les descripteurs d'écriture sont fermés, une fin de fichier est perçue sur le descripteur de lecture : read retourne 0. Un processus qui tente d'écrire dans un tube plein est suspendu jusqu'à ce que de la place se libère. On peut éviter ce blocage en positionnant le drapeau O_NDELAY (mais l'écriture peut n'avoir pas lieu). Lorsque read lit dans un tube insuffisamment rempli, il retourne le nombre d'octets lus. Attention : les primitives d'accès direct sont interdites; on ne peut pas relire les informations d'un tube car la lecture dans un tube est destructive. Dans le cas où tous les descripteurs associés aux processus susceptibles de lire dans un tube sont fermés, un processus qui tente de lire reçoit le signal 13 SIGPIPE et se trouve interrompu s'il ne traite pas ce signal. 3.1 Ecriture dans un tube fermé en lecture 3.1 Ecriture dans un tube fermé en lecture 3.1 Ecriture dans un tube fermé en lecture 3.1 Ecriture dans un tube fermé en lecture #include <errno.h> #include <signal.h> /****************************************************************/ void it_sigpipe () { printf ("On a recu le signal SIGPIPE\n"); } /****************************************************************/ void main () { int p_desc [2]; signal (SIGPIPE, it_sigpipe); pipe (p_desc); close (p_desc [0]); /* fermeture du tube en lecture */ if (write (p_desc [1], "0", 1) == -1) perror ("Erreur write : "); } Tester l'exécution de ce programme et expliquez son fonctionnement. Autres exemples intéressants : Jean-Pierre BRAQUELAIRE, "Méthodologie de la programmation en Langage C", Masson, 1993, p. 344-345, 456-457 Systèmes d'exploitation et programmation système Yves PAGNOTTE Chapitre 13 3 / 8 3.2 Lecture dans un tube fermé en écriture. 3.2 Lecture dans un tube fermé en écriture. 3.2 Lecture dans un tube fermé en écriture. 3.2 Lecture dans un tube fermé en écriture. #include <errno.h> #include <signal.h> /****************************************************************/ void main () { int i , ret , p_desc [2]; char c; pipe (p_desc); write (p_desc[1], "AB", 2); close (p_desc [1]); for (i = 1; i <= 3; i++) { ret = read (p_desc [0], &c, 1); if (ret == 1) printf ("valeur lue : %c\n", c ); else perror ("lecture impossible : "); } Tester l'exécution de ce programme et expliquez son fonctionnement 4. EXEMPLES DE PROGRAMMES. 4. EXEMPLES DE PROGRAMMES. 4. EXEMPLES DE PROGRAMMES. 4. EXEMPLES DE PROGRAMMES. 4.1 Communication père 4.1 Communication père 4.1 Communication père 4.1 Communication père- - - -fils fils fils fils Un fils hérite des tubes créés par le père et de leurs descripteurs. /* exemple 1 */ #include <stdio.h> #include <errno.h> #define TAILLE 30 /* par exemple */ main () { char envoi [TAILLE], reception [TAILLE];`int p [2], i, pid; strcpy (envoi, "texte transmis au tube"); if (pipe (p) < 0) { perror ("erreur de création du tube "); exit (1); } if ((pid = fork()) == -1) { perror ("erreur au fork "); exit (2); } if (pid > 0) /* le père écrit dans le tube */ { for (i=0 ; i<5; i++) write (p[1], envoi, TAILLE); wait (0); } if (pid == 0) /* le fils lit dans le tube */ { for (i=0 ; i<5 ; i++) read (p[0], reception, TAILLE); printf (" --> %s\n", reception); exit (0); } } Testez l'exécution de ce programme. Systèmes d'exploitation et programmation système Yves PAGNOTTE Chapitre 13 4 / 8 /* exemple 2 */ #include <stdio.h> #include <errno.h> #define NMAX 10 /* par exemple */ /**************************************************************/ void main () { int pid , p_desc [2]; char c; if (pipe (p_desc)) { perror ("erreur en creation du tube "); exit (1); } if ((pid = fork ()) == -1) { perror ("echec du fork "); exit (2); } if (pid == 0) { char t [NMAX]; int i=0; close (p_desc [1]); while (read (p_desc [0], &c, 1)) if (i < NMAX) t[i++] = c; t [( i == NMAX) ? NMAX-1 : i ] = 0; printf ("t : %s\n", t); } else { close p_desc [0]); while ((c = getchar ()) != EOF) if (c ≥ 'a' && c ≤ 'z') write (p_desc [1], &c, 1); close p_desc [1]); wait (0); } } /* exemple 3 */ #include <stdio.h> #include <errno.h> #define NMAX 10 /* par exemple */ /**************************************************************/ void main () { int pid , p_desc [2] , m; FILE *in, *out; if (pipe (p_desc)) { perror ("erreur en création du tube "); exit (1); } out = fdopen (p_desc [0], "r"); in = fdopen (p_desc [1], "w"); if ((pid = fork ()) == -1) { perror ("echec du fork "); exit (2); } if (pid == 0) { int t[NMAX], i = 0; fclose (in); while (fscanf (out, "%d", &m) != EOF) if (i <NMAX) t[i++] = m; Systèmes d'exploitation et programmation système Yves PAGNOTTE Chapitre 13 5 / 8 t ( [ i == NMAX) ? NMAX-1 : i ] = 0; for (m=0 ; m < i ; m++) printf ("%d \n", m); } ..................................... cf. exemple 2 ................................. } Testez l'exécution de ces programmes et expliquez leur fonctionnement. Autres exemples intéressants : Braquelaire p. 465-467. 4.2 H 4.2 H 4.2 H 4.2 Héritage des descripteurs lors d'un fork éritage des descripteurs lors d'un fork éritage des descripteurs lors d'un fork éritage des descripteurs lors d'un fork #include <errno.h> #include <stdio.h> /****************************************************************/ void code_fils (int numero) { int fd, nread; char texte [100]; fd = numero; printf ("le descripteur est : %d\n", fd); switch (nread = read (fd, texte, sizeof (texte))) { case -1 : perror (" erreur read : "); break; case 0 : perror ("erreur EOF"); break; default : printf ("on a lu %d caractères : %s\n", nread, texte); } } /****************************************************************/ void main () { int p_desc [2], char chaine [10]; if (pipe (p_desc )) { perror ("erreur en creation du tube "); exit (1); } uploads/Litterature/ chapitre-13.pdf
Documents similaires
-
12
-
0
-
0
Licence et utilisation
Gratuit pour un usage personnel Attribution requise- Détails
- Publié le Fev 18, 2022
- Catégorie Literature / Litté...
- Langue French
- Taille du fichier 0.1125MB