next up previous contents
Next: Utilisation d'un descripteur existant Up: Les pipes Previous: Fonctionnement   Contents

Programmation

L'initialisation d'un pipe se fait par le biais de la fonction :


       int pipe(int filedes[2]);

Cette fonction créé un pipe avec 2 descripteurs (filedes[0] en entrée, filedes[1] en sortie). Elle retourne -1 en cas d'erreur (appel système), 0 sinon. On peut ensuite envoyer (write()) ou recevoir (read()) des informations sur le pipe. Le seul problème est que l'on ne sait pas a priori la taille des informations qui transitent sur le pipe.

Pour cela, on peut utiliser une structure de contrôle appelée stat qui permet de récupérer les informations concernant le pipe. La fonction correspondante est :


int fstat(int filedes, struct stat *buf);

filedes est le descripteur du fichier et buf pointe sur une structure de type stat (inclure $<sys/types.h>$ et $<sys/stat.h>$).

[linewidth=1pt,fillstyle=solid,shadow=true](-0.5,0)(17.5,-16)

Un exemple utilisant ce procédé est donné ci-dessous :


#include <stdio.h>  <sys/types.h> 
#include <string.h> <sys/stat.h>

void main()
{
   int status,pipedes[2];
   char buff[100];
   int len;
   char *msg="Salut Fred !";
   struct stat pipestat;

   if (pipe(pipedes))     exit(1);
   if (fork())         
   {  /* Code du pere */
      write(pipedes[1],msg,strlen(msg));
      wait(&status);
      return;
   }
   else
   {   /* Code du fils */
       while(len==0) /* Attend que le pipe soit rempli */
       {
           if (fstat(pipedes[0],&pipestat))   exit(3);
           len=(int)pipestat.st_size;
       }
       read(pipedes[0],buf,len);
       printf("Mon pere adore l'art de decaler les sons : %s\n",buf);
       return;
   }

}

Si plusieurs processus sont susceptibles d'utiliser un même pipe, il est nécessaire de synchroniser les accès au pipe par signaux (voir plus loin), ou ouvrir 2 pipes utilisés chacun pour un dialogue spécifique (fils vers père et père vers fils par exemple).

[linewidth=1pt,fillstyle=solid,shadow=true](-0.5,0)(17.5,-22)

Dans l'exemple ci-dessous, le père crée un fils et lui envoie un message, puis le fils accuse réception du message. Les descripteurs inutiles sont fermés.


#include <stdio.h>

int pipdes1[2],pipdes2[2];

void fils()
{
  char buff[21];
 
  /* Fermeture du pipe 1 en ecriture et 0 en lecture */
  close(pipdes1[1]);
  close(pipdes2[0]);

  read(pipdes1[0],buff,21);
  printf("fils : %s\n",buff);
  write(pipdes2[1],"Message recu",13);
  return(0);
}

void main()
{
  int status;
  char bufp[13];

  if (pipe(pipdes1))    exit(1);
  if (pipe(pipdes2))    exit(1);

  if (fork())
    {
      /* Fermeture du pipe 0 en ecriture et 1 en lecture */
      close(pipdes1[0]);
      close(pipdes2[1]);
      write(pipdes1[1],"Salut les process...",21);
      read(pipdes2[0],bufp,13);
      printf("Pere: %s\n",bufp);
      wait(&status);
      exit(0);
    }
  else
    {
      fils();
    }
}

Dans les exemples ci-dessus, le fils récupère le descripteur grâce à la conservation des informations de fichiers ouverts par le fork. Par contre, si le fils est mis en place par un exec, les descripteurs de fichiers (et donc de pipe) sont oubliés. Il est donc nécessaire de transmettre le descripteur du pipe au fils.

[linewidth=1pt,fillstyle=solid,shadow=true](-0.5,0)(17.5,-24.5)

L'exemple ci-dessous montre comment passer le numéro du pipe en argument.


/* Programme du pere */
#include <stdio.h> <sys/types.h> <sys/stat.h>

void main()
{
  int pipdes[2],status,len;
  char msg[80],buf[11];
  struct stat pipestat;

  if (pipe(pipdes))     exit(1);
  /* Conversion du descripteur en chaine de caracteres */
  printf(buf,"%d",)pipdes[1]);

  if (fork())
    {
      close(pipdes[1]);
      do        
        {       
          if (fstat(pipdes[0],&pipestat))       exit(2);
          len=(int)pipestat.st_size;
        }
      while(len==0);

      if (read(pipdes[0],msg,len)!=len) exit(3);
      msg[len]=0;
      printf("%s\n",msg);
      wait(&status);
      exit(0);
    }
  else
    {
      execl("pipe_fils1","pipe_fils1",buf,0);
    }
}

/* Programme du fils : pipe_fils1 */

#include <stdio.h> <stdlib.h>

void    main(int argc, char ** argv)
{
  int idpip;
  char *msg="Salut papa, je suis ton fils";

  /* Conversion du premier argument en numero de descripteur */
  idpip=(int)atoi(argv[1]);
  if (write(idpip,msg,strlen(msg))!=strlen(msg))        exit(1);
  exit(0);
}



Subsections
next up previous contents
Next: Utilisation d'un descripteur existant Up: Les pipes Previous: Fonctionnement   Contents
Arnaud Revel
2001-11-26