Vous êtes sur la page 1sur 29

Tubes

• Un tube de communica.on est un tuyau (pipe) dans lequel deux ou plusieurs processus peuvent
échanger des informa.ons : un peut écrire des données et un autre peut lire

• int pipe (int descripteur[2]); // Dans unistd.h


renvoie 0 en cas de succès

• pipe remplit le tableau descripteur passé en paramètre


• descripteur[0] : sor.e du tube (dans laquelle on peut lire des données)
• descripteur[1] : entrée du tube (dans laquelle on peut écrire des données)

• Principe :
• Un processus écrit dans descripteur[1]
• Un autre va lire les mêmes données dans descripteur[0]
• Seuls les descendants du processus créateur du tube et lui-même peuvent l’u.liser
• Toute lecture est destruc.ve
• Le tube est unidirec.onnel
Communica)on inter-processus par tube
• Communica)on via un tube (On suppose que le père écrit dans le tube alors que le fils lit)
1. Le processus crée le tube
2. Le processus fait un appel à fork() pour créer un fils.
3. Les deux processus père et fils possèdent alors chacun un descripteur en lecture et en
écriture sur le tube.
4. Le processus père ferme son descripteur en lecture. Le processus fils ferme son descripteur
en écriture sur le tube.
5. Le processus père peut écrire sur le tube ; les valeurs écrites pourront être lues par le fils.
Communica)on inter-processus par tube
• ssize_t read(int fd0, void *buf, size_t taille)
lit jusqu’à taille octets depuis le descripteur de fichier fd0 dans le tampon pointé par buf

Par exemple,
char buf[100];
int p[2];
n=read(p[0], buf, 20); à n <= 20

• Si le tube ne conGent aucun caractère (tube vide), deux cas possibles


• Il y a encore des écrivains suscepGbles d’écrire dans le tube (il existe un descripteur p[1] encore ouvert);
à read() se met en aLente de lecture; lecture bloquante
• Aucun autre processus ne déGent de descripteur en écriture sur ce fichier à fin de fichier, read()
renvoie 0; la seule façon de terminer les lectures dans un tube (p.e. dans une boucle while) à close
p[1] de tous les descripteurs d’écriture du tube
Communica)on inter-processus par tube
• ssize_t write(int fd1, const void*buf, size_t taille)
Ecrit jusqu’à taille octets dans le fichier associé au descripteur fd1 depuis le tampon pointé par
buf

char buf[100];
int p[2];
sprintf(buf, "texte à écrire ");
write(p[1], buf, 20);
• S’il n’y a aucun lecteur sur le tube (tous les descripteurs en lecture sont fermés) à erreur fatale, le
processus écrivain renvoie le signal SIGPIPE
• Sinon, s’il y a de la place , les caractères sont écrits à write renvoie le nombre de caractères
Sinon à écriture bloquante jusqu’à ce qu’il y ait de la place

• int close (int fd)


ferme le descripteur en lecture ou en écriture
Communica)on inter-processus par tube
• Descripteur de fichiers standard

• Descripteur de fichier 0 : stdin

• Descripteur de fichier 1 : stdout

• Descripteur de fichier 2 : stderr

• Automa7quement ouverts pour chaque processus


Communica)on inter-processus par tube
• int open(const char*path, int oflags)
transforme un chemin d’un fichier en un descripteur manipulable par les fonc5ons C.
Si ce9e transforma5on est réussie, le descripteur du fichier est retourné. Le descripteur de fichier
retourné est unique et ce9e valeur ne peut pas être partagée donc avec d’autre processus en cours
d’exécu5on. Si deux processus ouvrent le même fichier, ils auront deux valeurs dis5nctes de
descripteurs.
• Le chemin du fichier est spécifié dans la variable path tandis que oflags indique les ac5ons à
entreprendre à l’ouverture du fichier. On spécifie ces ac5ons avec une combinaison d’ac5ons
obligatoires et d’autres op5onnelles.
Les ac5ons obligatoires concernent le type d’ouverture :
• O_RDONLY : ouvre le fichier en lecture seulement
• O_WRONLY : ouvre le fichier en écriture seulement
• O_RDWR : ouvre le fichier en écriture et lecture
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *path, int oflags);
Communica)on inter-processus par tube
• Les ac'ons op'onnelles sont :
• O_APPEND : les données écrites sont placées à la fin du fichier
• O_TRUNC : la longueur du fichier est mise à zéro
• O_CREAT : créa'on du fichier seulement si il n’existe pas déjà. Les permissions ini'ales sont indiquées par la
variable mode.
• O_EXCL : u'lisé avec O_CREAT pour assurer que l’appel de la fonc'on va effec'vement créer le fichier.
• Pour faire une combinaison des commandes (obligatoires et op'onnelles) on u'lise l’opérateur ou
binaire |. Par exemple :
O_CREAT | O_WRONLY | O_TRUNC
ouvre un fichier en écriture, avec créa'on si c’est nécessaire, et met son contenu à zéro.
Communica)on inter-processus par tube
• Exemple d’ouverture de fichier :
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

fd_in=open(nomfichier, O_RDONLY); //nomfichier est le nom du fichier qu'on va lire
if (fd_in == -1 ) {
perror("open du fichier");
exit(-1);
}
Communica)on inter-processus par tube
• Ecrire un programme qui crée deux processus : le père écrit un message, le fils le récupère et
l’affiche
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define BUFFER_SIZE 256
int main() {
pid_t pid_fils;
int tube[2];
unsigned char bufferR[256], bufferW[256];
puts( " créaXon d’un tube " );
if (pipe(tube) != 0) {/* pipe */
Communica)on inter-processus par tube
fprin&(stderr, "Erreur dans pipe\ n");
exit(1);
}
pid_fils = fork(); /* fork */
if (pid_fils == -1)
{
fprin&(stderr, "Erreur dans fork\n");
exit(1);
}
if (pid_fils == 0) /* processus fils */
{
prin&("Fermeture entree dans le fils (pid = %d)\n", getpid());
close(tube[1]);
Communica)on inter-processus par tube
read(tube[0], bufferR, BUFFER_SIZE);
prin=("Le fils (%d) a lu : %s\n", getpid(), bufferR);
}
else /* processus pere */
{
prin=("Fermeture sorNe dans le pere (pid = %d)\n", getpid());
close(tube[0]);
sprin=(bufferW, "Message du pere (%d) au fils", getpid());
write(tube[1], bufferW, BUFFER_SIZE);
wait(NULL);
}
return 0;
}
Communica)on inter-processus par tube

Ø ./tube
création d’un tube
Fermeture sortie dans le pere (pid = 744)
Fermeture entree dans le fils (pid = 746)
Le fils (746) a lu : Message du pere (744) au fils
Communica)on inter-processus par tube
• Transmission binaire
Exemple qui saisit une valeur au clavier dans le père et transmet la racine carrée de ce nombre en
tant que double au fils
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <math.h>
int main() {
pid_t fils;
int tube[2];
double x, y, z;
Communica)on inter-processus par tube
puts("Créa+on d'un tube");
if (pipe(tube) != 0) /* pipe */
{
fprin=(stderr, "Erreur dans pipe\n");
exit(1);
}
switch(pid_fils = fork()) /* fork */
{
case -1 : perror("Erreur dans fork\n"); exit(errno);
case 0 : /* processus fils */
close(tube[1]);
read(tube[0], &z, sizeof(double));
prin=("Le fils (%d) a lu : %.2f\n", getpid(), z); break;
Communica)on inter-processus par tube
default : /* processus père */
prin4("Fermeture sor9e dans le père (pid = %d)\n", getpid());
close(tube[0]);
puts("Entrez x :");
scanf("%lf", &x);
y = sqrt(x);
write(tube[1], &y, sizeof(double));
wait(NULL); break;
}
return 0;
}
Communica)on inter-processus par tube
• Le programme suivant lit des caractères sur l’entrée standard et envoie et envoie les lettres et
chiffres à son processus fils. Le fils compte les lettres et les chiffres et affiche le résultat. Le père
attend la terminaison du fils.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
int main() {
pid_t retour ;
int tube[2], lettre = 0, chiffre = 0 ;
char k ;
if (pipe (tube) == -1) {
perror ("creation pipe impossible\n") ; exit (1) ;
}
Communica)on inter-processus par tube
switch (retour = fork ()) {
case -1 : perror ("Crea9on impossible") ;
exit(1) ;
case 0 : prinA ("processus fils\n") ;
close (tube[1]) ;
while (read (tube[0], &k, 1) >0)
if (isdigit (k)) chiffre++ ;
else leMre++ ;
prinA ("%d chiffres recus\n", chiffre) ;
prinA ("%d leMres recues\n", leMre) ;
exit (0) ;
default :
Communica)on inter-processus par tube
prin% ("pere: a cree processus %d\n", retour) ;
close (tube[0]) ;
while (read (0, &k, 1) >0) /* lecture du clavier */
if (isalnum(k)) write (tube[1], &k, 1) ;
/* le tube est ici ferme en ecriture : un read sur le tube vide retournera 0 dans le
processus fils */
close (tube[1]) ;
wait (NULL) ;
prin% ("pere: a recu terminaison fils\n") ;
}
}
Communica)on inter-processus par tube
Ø ./tube_3
pere: a cree processus 346
processus fils
ztb;628?.rt5^D
4 chiffres recus
5 le@res recues
pere: a recu terminaison fils
Communica)on inter-processus par tube
• Communication bi-directionnelle entre père et fils (il faut 2 tubes !)
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main () {
int pip1[2]; int pip2[2];
pid_t pid_fils;
char chaine1[7], chaine2[5];
/* Création des tubes */
if(pipe(pip1) == -1) {
perror("pipe 1");
exit(1);
}
Communica)on inter-processus par tube
if(pipe(pip2) == -1) {
perror("pipe 2");
exit(2);
}
/* créa9on processus */
pid_fils = fork();
if (pid_fils == -1) {
perror ("Crea9on impossible") ;
exit(3) ;
}
if (pid_fils > 0) {
/* tube père vers fils */
/* fermé en lecture */
close (pip1[0]);
/* second tube fils vers père */
/* fermé en écriture */
close (pip2[1]);
Communica)on inter-processus par tube
/* envoi message au fils par le tube 1*/
if(write(pip1[1],"hello",5)!=5) {
fprinB(stderr,"père: erreur en écriture\n");
exit(4);
}
/* ANente de la réponse du fils par le tube 2 */
if(read(pip2[0],rep,7)!=7) {
fprinB(stderr,"fils: erreur lecture\n");
exit(5);
}
prinB("message du fils: %s\n",rep);
wait(&status);
}
Communica)on inter-processus par tube
else {
/*fermeture du tube 1 en écriture */
close(pip1[1]);
/* fermeture du tube 2 en lecture */
close(pip2[0]);
/* a>ente d’un message du père */
if(read(pip1[0],mesg,5)!=5) {
fprinF(stderr,"fils: erreur lecture\n");
exit(6);
}
prinF("la chaine reçue par le fils est: %s\n",mesg);
/* envoi d’un message au père */
if(write(pip2[1],"bonjour",7)!=7) {
fprinF(stderr,"fils: erreur ecriture\n"); exit(7);
}
exit(0);
}
}
Entrées-sor*es et tubes
• On peut lier la sortie d’un tube à stdin (1) ou l’entrée d’un tube à stdout (2)
• (1) à toutes les informations qui sortent du tube arrivent dans le flot d’entrée standard et peuvent être lues avec
scanf, gets,…
• (2) à toutes les informations qui sortent par stdout sont écrites dans le tube. On peut utiliser printf, puts,…

• int dup2 (int ancien descripteur, int nouveau descripteur) permet de dupliquer les entrées de la
table des descripteurs
• Duplication des descripteurs
• Rediriger les entrées-sorties standard d’un processus sur un tube
ancien descripteur : descripteur[0] si on veut lier la sortie
descripteur[1] si on veut lier l’entrée

nouveau descripteur : STDIN_FILENO lorsqu’on veut lier la sortie à stdin


STDOUT_FILENO lorsqu’on veut lier l’entrée à stdout
Entrées-sor*es et tubes
Pour lier la sor+e à stdin Pour lier l’entrée à stdout

int tube[2], a5ributs; int tube[2], a5ributs;


….. …..
pipe (tube); …. pipe (tube); ….
dup2(tube[0], STDIN_FILENO); dup2(tube[1], STDOUT_FILENO);
close (tube[0]); close (tube[1]);
… …
Entrées-sor*es et tubes (exemple redirec*on)
• Nombre de lignes de
Ø cat file1.dat | wc -l
Entrées-sor*es et tubes (exemple redirec*on)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main (int argc, char * argv[]) {
int tubeDesc[2];
pid_t pid_fils;
if( argc != 2) {
prinI ( "Erreur : syntaxe : commande nomfic"); exit(1);
}
if (pipe (tubeDesc) == -1) {
perror ("pipe");
exit (2);
}
Entrées-sorties et tubes (exemple redirection)
if ( (pid_fils = fork ( )) == -1 ){
perror ("fork");
exit (1);
}
if (pid_fils == 0) { /* fils */
dup2(tubeDesc[1],STDOUT_FILENO); /* lier l’entrée à stdout */
close (tubeDesc[1]);
close (tubeDesc[0]); /* fermeture en lecture */
if (execlp ("cat", "cat", argv[1],NULL) == -1) {
perror ("execlp");
exit (1);
}
}
Entrées-sor*es et tubes (exemple redirec*on)
else { /* père */
dup2(tubeDesc[0],STDIN_FILENO); /* lier la sorEe à stdin */
close (tubeDesc[0]);
close (tubeDesc[1]); /* fermeture en écriture */
if (execlp ("wc", "wc", "-l", NULL) == -1) {
perror ("execl");
exit (1);
}
}
return (EXIT_SUCCESS);
}

Vous aimerez peut-être aussi