C의 파이프에서 데이터 읽기
이 기사는 C에서 파이프에서 읽는 방법에 대한 여러 방법을 보여줍니다.
pipe
및read
시스템 호출을 사용하여 C의 파이프에서 읽기
파이프는 UNIX 기반 시스템에서 프로세스 간 통신 (IPC) 기본 요소의 변형 중 하나입니다. 단방향 통신 채널, 즉 두 프로세스 간의 바이트 스트림을 제공하며 데이터는 한 방향으로 순차적으로 이동합니다. pipe
시스템 호출은 파이프를 만들고 읽기 및 쓰기 종료를위한 파일 설명자를 획득하는 데 사용됩니다. 일반적인 I/O 함수read
및write
를 사용하여 파이프 디스크립터에서 작업 할 수 있습니다. 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);
}
}
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