티스토리 뷰
☞ pipe, popen, pclose, mkfifo
<unistd.h>
<sys/stat.h>
int pipe(intfiledes[2]);
FILE *popen(const char *command, const char *mode);
int pclose(FILE *stream);
int mkfifo(const char *filename, mode_t mode);
파이프(Pipe)는 두 프로세스 간에 수행 할 수 있는 통신 방법의 하나로 한 프로세스가 쓰기하면 다른 프로세스가 읽을 수 있습니다. 다른 파일같은 이름을 가지지 못합니다.
FIFO는 특수 파일의 하나로 파이프와 유사하지만 일반적인 파일 처럼 이름을 가지고 접근합니다.
파이프나 FIFO는 양쪽 프로세스에서 동시에 오픈해야만 합니다. 쓰기하는 프로세스가 없는데 파이프나 FIFO를 읽으면 파일 끝을 인지하게 되고 읽는 프로세스가 없는데 쓰기하면 에러가 발생합니다.
또한, 파이프와 FIFO는 순차적 접근만 가능해서 임의 접근을 허용하는 파일과 달리 파일 위치 변경을 할 수 없습니다.
pipe()는 입출력 파일 디스크립터를 받을 정수 배열을 인수로 받아 파이프를 생성합니다.
성공하면 0, 실패하면 -1을 리턴하는데 파이프가 생성되면 배열 첫 원소에 입력(읽기), 두번째 원소에 출력(쓰기) 디스크립터가 저장됩니다.
통상 fork()로 자 프로세스를 생성한 다음 부모 프로세스와 자 프로세스 간의 통신에 사용합니다.
☞ 예제1
static int dl_open_pipe (int *fd, int lineno) { int result = pipe (fd); return result; } static void dl_spawn_daemon (DYNAMIC_LOADER * this_) { int fd[2]; int daemon_pid; assert (this_ != NULL); if (this_->daemon.daemon_fd != DAEMON_NOT_SPAWNED) { return; } if (PIPE (fd) == -1) { /* pipe creation failed */ er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_DL_DAEMON_MISSING, 0); this_->daemon.daemon_fd = DAEMON_NOT_AVAILABLE; return; } daemon_pid = (*this_->fork_function_p) (); if (daemon_pid) { /* This is the parent process. */ if (daemon_pid == -1) { er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_DL_DAEMON_MISSING, 0); CLOSE (fd[0]); CLOSE (fd[1]); this_->daemon.daemon_fd = DAEMON_NOT_AVAILABLE; return; } dl_set_pipe_handler (); CLOSE (fd[0]); this_->daemon.daemon_fd = fd[1]; /* write side of the pipe */ } else { /* This is the child process. */ int i; if (dup2 (fd[0], 0) == -1) /* read side of the pipe */ { _exit (1); } for (i = 1; i < NOFILE; ++i) { close (i); /* Close all file descriptors except stdin */ } execl (this_->daemon.daemon_name, (char *) 0); _exit (1); } }
위의 큐브리드 DBMS 코드에서는 pipe()로 파이프를 생성하고 fork()이후 부모 프로세스에서는 읽기 디스크립터를 닫고, 자 프로그램에서는 쓰기 디스크립터를 닫는 과정을 참조할 수 있습니다. 또한 자 프로세스에서 생성한 파이프를 dup2()로 표준 입력으로 처리하는 과정과 execl()로 외부 프로그램을 호출할때 표준 입력을 그대로 넘기는 과정도 참고할만 합니다.
☞ 예제2
...... snprintf (cmd_line, sizeof (cmd_line), "addr2line -f -C -e %s %p 2>/dev/null", lib_file_name_p, address); output = popen (cmd_line, "r"); ......
popen(), pclose()는 앞선 예제의 경우 pipe(), fork(), dup2(), exec()로 이어지는 통신 과정이 있었으나 popen()은 이 과정을 단순하고 편리하게 사용할 수 있도록 해줍니다. command에 수행할 외부 프로그램명을 기술하고 mode에 "r"을 지정하면 외부 프로그램의 표준 출력을 스트림 입력으로 사용할 수 있습니다. mode에 "w"을 지정하면 외부 프로그램의 표준 입력으로 스트림 출력을 내보낼 수 있습니다. 예를 들어 "more"와 같은 콘솔 명령으로 스트림 출력을 내보내어 한번에 한 화면씩 출력하도록 조정할 수 있습니다.
☞ 예제3
...... char * myfifo = "/tmp/myfifo"; mkfifo(myfifo, 0666); ...... fd = open(myfifo, O_WRONLY); write(fd, output_str, strlen(output_str)+1); close(fd); ...... fd = open(myfifo, O_RDONLY); read(fd, readbuf, sizeof(readbuf)); printf("Message: %s\n", readbuf); close(fd); ......
mkfifo()는 일반 파일 처럼 open()으로 열고 close()로 닫아서 사용할 수 있는 특수 파일을 생성합니다. 파일 시스템에 생성하여 하나의 프로세스는 순차적 쓰기, 다른 한 프로세스는 순차적 스트림 읽기를 수행할 수 있습니다. 파이프와 유사하지만 일반 파일처럼 파일 시스템의 특정한 파일명으로 통신 채널을 지정한다는 차이점이 있습니다. 일반 파일과의 차이점은 두 프로세스가 동시에 FIFO를 열어야 동작할 수 있습니다. 예를 들어 FIFO를 O_RDONLY 모드로 생성하는 프로세스는 FIFO를 O_WRONLY 모드로 생성하는 프로세스가 동작할 때 까지 대기하게 됩니다. 통상 정상 동작하면 0, 실패하면 -1을 리턴합니다.
'C | C++' 카테고리의 다른 글
인터넷 네임 스페이스 (0) | 2018.06.17 |
---|---|
소켓 주소 다루기 (0) | 2018.06.17 |
임시 파일 사용하기 (0) | 2018.06.17 |
파일 속성 다루기 (0) | 2018.06.17 |
파일 링크 (0) | 2018.06.17 |