Leggi i dati dalla pipe in C

Jinku Hu 12 ottobre 2023
  1. Usa le chiamate di sistema pipe e read per leggere da pipe in C
  2. Usa il cicli while per leggere dal pipe in C
Leggi i dati dalla pipe in C

Questo articolo illustrerà più metodi su come leggere dalla pipe in C.

Usa le chiamate di sistema pipe e read per leggere da pipe in C

La pipe è una delle varianti delle primitive di comunicazione interprocesso (IPC) nei sistemi basati su UNIX. Fornisce un canale di comunicazione unidirezionale, vale a dire un flusso di byte tra due processi, ei dati vengono spostati sequenzialmente in una direzione. La chiamata di sistema pipe è usata per creare una pipe e acquisire descrittori di file per le sue estremità di lettura e scrittura. Notare che possiamo operare sui descrittori di pipe con le normali funzioni di I/O read e write. La chiamata di sistema pipe accetta un array int a due elementi e la chiamata riuscita restituisce due descrittori di file che denotano la fine del primo - lettura e del secondo - scrittura. Tieni presente che i dati scritti sulla pipe vengono memorizzati nel buffer fino a quando il lettore non recupera i byte specificati.

Nell’esempio seguente, viene illustrato l’utilizzo di base di pipe per comunicare tra i processi padre e figlio. All’inizio, creiamo una pipe e memorizziamo i suoi descrittori nell’array pipe_fd. Successivamente, chiamiamo fork in un’espressione di istruzione switch e includiamo il blocco di codice del processo figlio sotto il caso 0. Il caso default, d’altra parte, verrà eseguito dal processo genitore.

Si noti che il genitore scrive la stringa che è stata recuperata dall’argomento della riga di comando e quindi attende che il figlio termini. Nel frattempo, il processo figlio legge dalla pipe e stampa i byte letti sulla console. Sia il figlio che il genitore chiudono un’estremità della pipe perché il processo figlio eredita i descrittori di file del genitore su fork. Infine, dopo che i byte inviati sono stati letti, l’estremità di lettura della pipe viene chiusa dal figlio, terminando con una chiamata di 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);
  }
}

Usa il cicli while per leggere dal pipe in C

Il codice di esempio precedente ha un bug ingannevole che può produrre una lettura parziale nel processo figlio. La chiamata read può restituire meno dati rispetto alla pipe, quindi chiamare una chiamata read in questo esempio sarebbe errato. Fortunatamente, la funzione read restituisce il numero di byte letti e possiamo implementare un bucle che esaurisce i dati nella pipe, come mostrato nel prossimo esempio di codice. Si noti che i tubi hanno una capacità fissa e, se viene raggiunto il massimo, le operazioni di scrittura si bloccheranno fino a quando il lettore non avrà recuperato alcuni dati.

#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);
  }
}
Autore: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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