Notice
Recent Posts
Recent Comments
Link
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
03-29 07:35
관리 메뉴

nomad-programmer

[Programming/C] pipe() 함수 본문

Programming/C

[Programming/C] pipe() 함수

scii 2020. 6. 19. 21:42

자식 프로세스가 생성하는 데이터를 실시간으로 읽는 방법

pipe() 함수는 데이터 스트림 두 개를 연다. 

#

데이터 스트림

0

표준 입력

1

표준 출력

2

표준 에러

3

파이프의 읽는 쪽 (ex: fd[0])

4

파이프의 쓰는 쪽 (ex: fd[1])

자식 프로세스가 부모 프로세스에 데이터를 보내야 하므로, 자식 프로세스의 표준 출력과 부모 프로세스의 표준 입력에 연결된 파이프가 필요하다. 파이프는 pipe() 함수로 생성한다.

이 함수는 연결된 두 스트림을 만들어 테이블에 추가한다. 한쪽 스트림에 쓴 데이터는 다른 쪽 스트림에서 바로 읽을 수 있다.

pipe() 함수가 디스크립터 테이블에 두 항목을 만들 때, 디스크립터들을 항목이 두 개 있는 배열에 저장한다.

// 디스크립터들이 배열에 저장됨
int fd[2];
if (pipe(fd) == -1) {
    fprintf(stderr, "error");
}

pipe() 함수는 파이프를 생성하고 만들어진 디스크립터를 알려준다. fd[1]은 파이프에 쓰는 디스크립터이며, fd[0]은 파이프로부터 읽는 디스크립터이다. 일단 디스크립터를 얻으면 부모와 자식 프로세스가 사용할 수 있다.

자식 프로세스의 데이터를 부모 프로세스에 넘긴다고 가정하고 예를 들자면...

자식 프로세스에서는 파이프의 읽는 쪽인 fd[0]을 닫고, 표준 출력이 fd[1] 디스크립터가 가리키는 스트림을 가리키게 변경한다.

// 자식 프로세스는 파이프로부터 읽지 않기 때문에 파이프의 읽는 쪽을 닫는다.
// 자식 프로세스는 표준 출력을 파이프의 쓰는 쪽으로 연결한다.
close(fd[0]);
dup2(fd[1], 1);

이렇게하면 자식 프로세스가 표준 출력으로 보내는 모든 데이터가 파이프에 쓰여진다.

부모 프로세스에서는 쓰지 않기 때문에 파이프의 쓰는 쪽인 fd[1]을 닫고 프로세스의 표준 입력을 디스크립터 fd[0]이 가리키는 스트림으로 리다이렉션한다.

// 부모 프로세스는 표준 입력을 파이프의 읽는 쪽으로 리다이렉션한다.
dup2(fd[0], 0);
close(fd[1]);

이제 자식 프로세스가 쓰는 모든 데이터를 부모 프로세스의 표준 입력을 통해 읽을 수 있다.

pipe() 함수 예제

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[]) {
    // 파이프를 생성한 후 디스크립터를 fd[0], fd[1]에 저장
    int fd[2];
    if (pipe(fd) == -1) {
        fprintf(stderr, "pipe error: %s\n", strerror(errno));
        return 1;
    }
    pid_t pid = fork();
    if (pid == -1) {
        fprintf(stderr, "fork error: %s\n", strerror(errno));
        return 1;
    }
    // 자식 프로세서가 처리하는 코드
    if (pid == 0) {
        // 표준 출력을 파이프의 쓰는 쪽으로 설정
        dup2(fd[1], 1);
        // 자식 프로세스는 파이프에서 읽지 않으므로 읽는 쪽을 닫는다.
        close(fd[0]);
        int ste = execlp("ps", "ps", "aux", NULL);
        if (ste == -1) {
            fprintf(stderr, "run error: %s\n", strerror(errno));
            return 1;
        }
    }
    // 부모 프로세스만 여기에 도달한다.
    // 표준 입력을 파이프의 읽는 쪽으로 리다이렉션한다.
    dup2(fd[0], 0);
    // 부모 프로세스는 파이프에 쓰지 않으므로 파이프의 쓰는 쪽을 닫는다.
    close(fd[1]);
    char line[255];
    // 표준 입력이 파이프에 연결되어 있으므로 표준 입력에서 읽는다.
    // fd[0]을 사용해도 된다.
    while (fgets(line, sizeof(line), stdin) != 0) {
        printf("%s", line);
    }

    return 0;
}

// 결과
/*

ps aux 명령의 결과가 출력된다.

*/

파이프는 프로세스를 연결하는 훌륭한 방법이다. 프로세스를 실행하고 환경을 제어할 뿐만 아니라 출력을 가져올 수 있다.

정리

부모와 자식 프로세스는 파이프로 통신한다.

pipe() 함수는 파이프와 2개의 디스크립터를 생성한다.

2개의 디스크립터는 파이프의 읽는 쪽과 쓰는 쪽이다.

표준 입력과 출력을 파이프로 리다이렉션할 수 있다.

부모와 자식 프로세서는 서로 파이프의 반대쪽을 사용한다.

파일에 기반한 파이프는 이름을 갖고 있다. (mkfifo())

파이프는 언제나 한 방향으로만 작동한다. 그러나 파이프를 두 개 만들어 하나는 부모가 자식에게, 다른 하나는 자식이 부모에게 데이터를 보낼 수 있다.

'Programming > C' 카테고리의 다른 글

[Programming/C] 소켓과 서버  (0) 2020.06.20
[Programming/C] 시그널 (Signal)  (0) 2020.06.20
[Programming/C] 입출력의 리다이렉션  (0) 2020.06.19
[Programming/C] fork() 함수  (0) 2020.06.19
[Programming/C] errno.h 헤더 파일  (0) 2020.06.19
Comments