Daten aus der Pipe in C lesen

Jinku Hu 12 Oktober 2023
  1. Verwenden Sie die Systemaufrufe pipe und read, um in C von Pipe zu lesen
  2. Verwenden Sie die while-Schleife, um aus dem Rohr in C zu lesen
Daten aus der Pipe in C lesen

In diesem Artikel werden verschiedene Methoden zum Lesen aus Pipe in C demonstriert.

Verwenden Sie die Systemaufrufe pipe und read, um in C von Pipe zu lesen

Die Pipe ist eine der Varianten von IPC-Grundelementen (Inter-Process Communication) in UNIX-basierten Systemen. Es stellt einen unidirektionalen Kommunikationskanal bereit, nämlich einen Bytestrom zwischen zwei Prozessen, und die Daten werden nacheinander in eine Richtung verschoben. Der Systemaufruf pipe wird verwendet, um eine Pipe zu erstellen und Dateideskriptoren für ihre Lese- und Schreibenden abzurufen. Beachten Sie, dass wir Pipe-Deskriptoren mit den üblichen E / A-Funktionen read und write bearbeiten können. Der Systemaufruf pipe nimmt ein Array mit zwei Elementen int an, und der erfolgreiche Aufruf gibt zwei Dateideskriptoren zurück, die das erste Lese- und das zweite Schreibende angeben. Beachten Sie, dass in die Pipe geschriebene Daten im Kernel gepuffert werden, bis der Leser die angegebenen Bytes abruft.

Im folgenden Beispiel zeigen wir die grundlegende Verwendung von Pipe für die Kommunikation zwischen den übergeordneten und den untergeordneten Prozessen. Zuerst erstellen wir eine Pipe und speichern ihre Deskriptoren im Array pipe_fd. Als nächstes rufen wir fork in einem switch-Anweisungsausdruck auf und fügen den Codeblock des untergeordneten Prozesses in den Fall 0 ein. Der Fall default wird dagegen vom übergeordneten Prozess ausgeführt.

Beachten Sie, dass das übergeordnete Element die Zeichenkette schreibt, die aus dem Befehlszeilenargument abgerufen wurde, und dann darauf wartet, dass das untergeordnete Element beendet wird. Währenddessen liest der untergeordnete Prozess aus der Pipe und druckt die gelesenen Bytes an die Konsole. Sowohl untergeordnetes als auch übergeordnetes Element schließen das eine Ende der Pipe, da der untergeordnete Prozess die Dateideskriptoren des übergeordneten Elements auf fork erbt. Nachdem die gesendeten Bytes gelesen wurden, wird das Leseende der Pipe vom Kind geschlossen und mit einem Aufruf exit beendet.

#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);
  }
}

Verwenden Sie die while-Schleife, um aus dem Rohr in C zu lesen

Der vorherige Beispielcode weist einen betrügerischen Fehler auf, der zum teilweisen Lesen im untergeordneten Prozess führen kann. Der Aufruf read gibt möglicherweise weniger Daten zurück als in der Pipe. Daher wäre das Aufrufen eines Aufrufs read in diesem Beispiel fehlerhaft. Glücklicherweise gibt die Funktion read die Anzahl der gelesenen Bytes zurück, und wir können eine Schleife implementieren, die die Daten in der Pipe erschöpft, wie im nächsten Codebeispiel gezeigt. Beachten Sie, dass Pipes eine feste Kapazität haben. Wenn das Maximum erreicht ist, werden die Schreibvorgänge blockiert, bis der Leser einige Daten abruft.

#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);
  }
}
Autor: 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

Verwandter Artikel - C Pipe