Lire les données de pipe en C
-
Utilisez les appels système
pipe
etread
pour lire à partir de pipe en C -
Utilisez la boucle
while
pour lire depuis un tuyau en C
Cet article présente plusieurs méthodes sur la façon de lire à partir pipe en C.
Utilisez les appels système pipe
et read
pour lire à partir de pipe en C
Le canal est l’une des variantes des primitives de communication inter-processus (IPC) dans les systèmes UNIX. Il fournit un canal de communication unidirectionnel, à savoir un flux d’octets entre deux processus, et les données sont déplacées séquentiellement dans une direction. L’appel système pipe
permet de créer un tube et d’acquérir des descripteurs de fichiers pour ses fins de lecture et d’écriture. Notez que nous pouvons opérer sur des descripteurs de tuyaux avec les fonctions d’E/S habituelles read
et write
. L’appel système pipe
prend un tableau int
à deux éléments et l’appel réussi renvoie deux descripteurs de fichier indiquant la première - lecture et la seconde - fin d’écriture. Notez que les données écrites dans le tube sont mises en mémoire tampon dans le noyau jusqu’à ce que le lecteur récupère les octets donnés.
Dans l’exemple suivant, nous démontrons l’utilisation de base de pipe pour communiquer entre les processus parents et enfants. Dans un premier temps, nous créons un tube et stockons ses descripteurs dans le tableau pipe_fd
. Ensuite, nous appelons fork
dans une expression d’instruction switch
et incluons le bloc de code du processus fils sous le cas 0
. Le cas default
, en revanche, sera exécuté par le processus parent.
Notez que le parent écrit la chaîne qui a été récupérée à partir de l’argument de ligne de commande, puis attend que l’enfant se termine. Pendant ce temps, le processus enfant lit à partir du canal et imprime les octets lus sur la console. L’enfant et le parent ferment tous deux l’extrémité du canal car le processus enfant hérite des descripteurs de fichier du parent sur fork
. Enfin, après la lecture des octets envoyés, l’extrémité de lecture du tube est fermée par l’enfant, se terminant par un appel exit
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
enum { BUF_SIZE = 4096 };
int main(int argc, char *argv[]) {
int pipe_fd[2];
char buf[BUF_SIZE];
ssize_t numRead;
if (argc != 2) {
fprintf(stderr, "Usage: %s string\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipe_fd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
switch (fork()) {
case -1:
perror("fork");
exit(EXIT_FAILURE);
case 0:
if (close(pipe_fd[1]) == -1) {
perror("close - parent");
exit(EXIT_FAILURE);
}
sleep(3);
numRead = read(pipe_fd[0], buf, BUF_SIZE);
write(STDOUT_FILENO, buf, numRead);
write(STDOUT_FILENO, "\n", 1);
if (close(pipe_fd[0]) == -1) {
perror("close");
exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
default:
if (close(pipe_fd[0]) == -1) {
perror("close - parent");
exit(EXIT_FAILURE);
}
if (write(pipe_fd[1], argv[1], strlen(argv[1])) != strlen(argv[1])) {
perror("write - partial/failed write");
exit(EXIT_FAILURE);
}
if (close(pipe_fd[1]) == -1) {
perror("close");
exit(EXIT_FAILURE);
}
wait(NULL);
exit(EXIT_SUCCESS);
}
}
Utilisez la boucle while
pour lire depuis un tuyau en C
L’exemple de code précédent a un bogue trompeur qui peut entraîner une lecture partielle dans le processus enfant. L’appel read
peut renvoyer moins de données que dans le tube, donc appeler un appel read
dans cet exemple serait erroné. Heureusement, la fonction read
renvoie le nombre d’octets lus, et nous pouvons implémenter une boucle qui épuise les données dans le tube, comme indiqué dans l’exemple de code suivant. Notez que les canaux ont une capacité fixe, et si le maximum est atteint, les opérations d’écriture seront bloquées jusqu’à ce que le lecteur récupère certaines données.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
enum { BUF_SIZE = 4096 };
int main(int argc, char *argv[]) {
int pipe_fd[2];
char buf[BUF_SIZE];
ssize_t numRead;
if (argc != 2) {
fprintf(stderr, "Usage: %s string\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipe_fd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
switch (fork()) {
case -1:
perror("fork");
exit(EXIT_FAILURE);
case 0:
if (close(pipe_fd[1]) == -1) {
perror("close - parent");
exit(EXIT_FAILURE);
}
while (1) {
numRead = read(pipe_fd[0], buf, BUF_SIZE);
if (numRead == -1) {
perror("read");
exit(EXIT_FAILURE);
}
if (numRead == 0) break;
if (write(STDOUT_FILENO, buf, numRead) != numRead) {
perror("write - partial/failed write");
exit(EXIT_FAILURE);
}
}
write(STDOUT_FILENO, "\n", 1);
if (close(pipe_fd[0]) == -1) {
perror("close");
exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
default:
if (close(pipe_fd[0]) == -1) {
perror("close - parent");
exit(EXIT_FAILURE);
}
if (write(pipe_fd[1], argv[1], strlen(argv[1])) != strlen(argv[1])) {
perror("write - partial/failed write");
exit(EXIT_FAILURE);
}
if (close(pipe_fd[1]) == -1) {
perror("close");
exit(EXIT_FAILURE);
}
wait(NULL);
exit(EXIT_SUCCESS);
}
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook