Les pipes et les FIFOs permettent de faire communiquer des processus d'une même machine : ce qu'un (ou plusieurs) processus écrit peut être lu par un autre.
Les FIFOs sont également appelés « tuyaux nommés ». Ce sont des objets visibles dans l'arborescence des fichiers et répertoires. Ce qu'un processus écrit dans une FIFO peut être lu immédiatement par d'autres processus.
#include <stdio.h>
int mkfifo (const char *path, mode_t mode);
La fonction mkfifo()
crée un FIFO ayant le chemin indiqué par
path
et les droits d'accès donnés par mode
. Si la création
réussit, la fonction renvoie 0, sinon -1. Exemple:
if(mkfifo("/tmp/fifo.courrier",0644) == -1)
perror("mkfifo");
Les FIFOS sont ensuite utilisables par open(), read(), write(), close(),
fdopen()
etc.
Exercice. Regarder ce qui se passe quand
sleep-write
).Exercice. Ecrire une commande mutex qui permettra de délimiter une section critique dans des shell-scripts. Exemple d'utilisation :
mutex -b /tmp/foobar
...
mutex -e /tmp/foobar
Le premier paramètre indique si il s'agit de verrouiller (-b
= begin)
ou de déverrouiller (-e
= end). Le second paramètre est le nom
du verrou.
Conseil : la première option peut s'obtenir en tentant de lire un jeton dans une FIFO. C'est la seconde option qui dépose le jeton. Prévoir une option pour créer une FIFO ?
On utilise un pipe (tuyau) pour faire communiquer un processus et un de ses descendants
ou des descendants - au sens large - du processus qui ont crée le tuyau.
#include <unistd.h>
int pipe(int filedes[2]);
L'appel pipe()
fabrique un tuyau de communication et renvoie dans
un tableau une paire de descripteurs. On lit à un bout du tuyau (sur
le descripteur de sortie fildes[0]
)
ce qu'on a écrit dans l'autre (filedes[1]
).
Voir exemple dans fork.
Les pipes ne sont pas visibles dans l'arborescence des fichiers et répertoires, par contre ils sont hérités lors de la création d'un processus.
La fonction socketpair()
(voir
socketpair) généralise la fonction
pipe
.
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
popen()
lance la commande décrite par la chaîne command
et retourne un flot.
Si type
est "r"
le flot retourné est celui
de la sortie standard de la commande (on peut y lire).
Si type
est "w"
c'est son entrée standard.
pclose()
referme ce flot.
Exemple : envoi d'un « ls -l
» par courrier
1 /* avis.c */
2 /* Illustration de popen() */
3 #include <sys/types.h>
4 #include <fcntl.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <stdio.h>
8 #define TAILLE_MAX_COMMANDE 100
9 int main(int argc, char *argv[])
10 {
11 char cmdmail[TAILLE_MAX_COMMANDE];
12 FILE *fls, *fmail;
13 int c;
14 if (argc != 2) {
15 fprintf(stderr, "Usage: %s destinataire\n", argv[0]);
16 exit(EXIT_FAILURE);
17 };
18 snprintf(cmdmail, TAILLE_MAX_COMMANDE, "sendmail %s",
19 argv[1]);
20 fmail = popen(cmdmail, "w");
21 if (fmail == NULL) {
22 perror("popen(sendmail)");
23 exit(EXIT_FAILURE);
24 };
25 fprintf(fmail, "Subject: ls -l\n\n");
26 fprintf(fmail, "Cher %s,\nvoici mon répertoire:\n", argv[1]);
27 fls = popen("ls -l", "r");
28 if (fls == NULL) {
29 perror("popen(ls)");
30 exit(EXIT_FAILURE);
31 };
32 while ((c = fgetc(fls)) != EOF)
33 fputc(c, fmail);
34 pclose(fls);
35 fprintf(fmail, "---\nLe Robot\n");
36 pclose(fmail);
37 exit(EXIT_SUCCESS);
38 }