C의 파이프에서 데이터 읽기

Jinku Hu 2023년10월12일
  1. piperead시스템 호출을 사용하여 C의 파이프에서 읽기
  2. while루프를 사용하여 C의 파이프에서 읽기
C의 파이프에서 데이터 읽기

이 기사는 C에서 파이프에서 읽는 방법에 대한 여러 방법을 보여줍니다.

piperead시스템 호출을 사용하여 C의 파이프에서 읽기

파이프는 UNIX 기반 시스템에서 프로세스 간 통신 (IPC) 기본 요소의 변형 중 하나입니다. 단방향 통신 채널, 즉 두 프로세스 간의 바이트 스트림을 제공하며 데이터는 한 방향으로 순차적으로 이동합니다. pipe시스템 호출은 파이프를 만들고 읽기 및 쓰기 종료를위한 파일 설명자를 획득하는 데 사용됩니다. 일반적인 I/O 함수readwrite를 사용하여 파이프 디스크립터에서 작업 할 수 있습니다. pipe시스템 호출은 두 요소의int배열을 취하고 성공적인 호출은 첫 번째 읽기 및 두 번째 쓰기 종료를 나타내는 두 개의 파일 설명자를 리턴합니다. 파이프에 기록 된 데이터는 판독기가 주어진 바이트를 검색 할 때까지 커널에 버퍼링됩니다.

다음 예에서는 상위 프로세스와 하위 프로세스간에 통신하기위한 파이프의 기본 사용법을 보여줍니다. 처음에는 파이프를 만들고 설명자를pipe_fd배열에 저장합니다. 다음으로,switch문 표현식에서fork를 호출하고 케이스0아래에 자식 프로세스의 코드 블록을 포함합니다. 반면에default케이스는 상위 프로세스에 의해 실행됩니다.

부모는 명령 줄 인수에서 검색된 문자열을 쓴 다음 자식이 종료 될 때까지 기다립니다. 한편 자식 프로세스는 파이프에서 읽고 읽은 바이트를 콘솔에 인쇄합니다. 자식 프로세스는 fork에서 부모의 파일 설명자를 상속하기 때문에 자식과 부모 모두 파이프의 한쪽 끝을 닫습니다. 마지막으로, 전송 된 바이트를 읽은 후 파이프의 읽기 끝은 하위에 의해 닫히고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);
  }
}

while루프를 사용하여 C의 파이프에서 읽기

이전 샘플 코드에는 자식 프로세스에서 부분 읽기를 생성 할 수있는 사기성 버그가 하나 있습니다. read호출은 파이프보다 적은 데이터를 리턴 할 수 있으므로이 예제에서 하나의read호출을 호출하면 오류가 발생합니다. 다행히도read함수는 읽은 바이트 수를 반환하고 다음 코드 샘플에서 볼 수 있듯이 파이프에서 데이터를 소진하는 루프를 구현할 수 있습니다. 파이프에는 고정 된 용량이 있으며 최대 값에 도달하면 판독기가 일부 데이터를 검색 할 때까지 쓰기 작업이 차단됩니다.

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

관련 문장 - C Pipe