(리눅스 시스템 프로그래밍) OS PIPE + C예제코드
by 줌코딩
Pipe란?
- OS에서 한 프로그램 프로세스에서 다른 프로세스로 정보를 전달하는 기술이다.
- IPC통신과 달리 한 방향으로만 통신이 가능하다.
- 파이프 자체는 fork함수에 의해 복사되지 않는다.
pipe() in c
- 각 프로세스에는 해당하는 메모리가 독립적으로 존재하기 때문에 메모리로 통신이 불가능하다.
- 이것은 fork()를 이용해서 child process가 생성되더라도 데이터를 주고 받을 방법이 없다는 것이다.
- 이 때문에 존재하는 것이 pipe() 이다. 이를 통해 서로 다른 프로세스가 데이터를 주고 받을 수 있다.
pipe(int fd[2]);
- pipe는 크기가 2인 int형 배열을 요구한다.
- fd[0] : 함수 호출 후 fd[0]에 입력 받을 수 있는 파일 디스크립터가 담김
- fd[1] : 함수 호출 후 데이터를 출력할 수 있는 파일 디스크립터가 담김
어렵다.. 이럴 땐 사용법부터 보자!
사용법
쓰는 내용은 fd[1]에다 적고,
write(fd[1], “내용”, 길이);
읽을 때는 fd[0]을 통해서 읽는다.
read(fd[0], buf, 길이);
예제를 보고 가자.
main()
int pipes[2] ;
int main() {
pid_t child_pid ;
int exit_code ;
if (pipe(pipes) != 0) {
perror("Error") ;
exit(1) ;
}
printf("%d %d\n", pipes[0], pipes[1]) ;
child_pid = fork() ;
if (child_pid == 0) {
child_proc() ;
}
else {
parent_proc() ;
}
wait(&exit_code) ;
exit(0) ;
}
- Line 1: pipe[2]라는 어레이를 준비한다.
- Line 7: pipe()로 어레이에 파일 디스크립터를 넣어준다.
- Line 11: 각각의 파일 디스크립터를 출력한다.
- Line 13: fork함수를 통해 child_pid를 생성한다.
void parent_proc() - input을 파이프를 통해서 보내줌
void parent_proc() {
char * buf = 0x0 ;
ssize_t s ;
size_t len = 0 ;
close(pipes[0]) ;
while ((s = getline(&buf, &len, stdin)) != -1) {
buf[s - 1] = 0x0 ;
ssize_t sent = 0 ;
char * data = buf ;
while (sent < s) {
sent += write(pipes[1], buf + sent, s - sent) ;
}
free(buf) ;
buf = 0x0 ;
len = 0 ;
}
close(pipes[1]) ;
}
- Line 6: 읽지 않을 것이므로 읽기용 파이프를 닫는다.
- Line 8: getline()함수를 통해서 인풋을 읽는다.
- Line 15: pipes[1]을 통해서 쓰기를 진행한다.
- Line 22: 쓰기용 pipe를 닫는다.
void child_proc() - 파이프로 전달된 내용을 프린트함
void child_proc() {
char buf[32] ;
ssize_t s ;
close(pipes[1]) ;
while ((s = read(pipes[0], buf, 31)) > 0) {
buf[s + 1] = 0x0 ;
printf(">%s\n", buf) ;
}
exit(0) ;
}
- Line 5: 쓰기용 파이프를 닫아준다.
- Line 7: 파이프의 내용을 읽어들인다.
- Line 11: 아예 프로세스를 종료해라.
최종 코드
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int pipes[2] ;
void parent_proc() {
char * buf = 0x0 ;
ssize_t s ;
size_t len = 0 ;
close(pipes[0]) ;
while ((s = getline(&buf, &len, stdin)) != -1) {
buf[s - 1] = 0x0 ;
ssize_t sent = 0 ;
char * data = buf ;
while (sent < s) {
sent += write(pipes[1], buf + sent, s - sent) ;
}
free(buf) ;
buf = 0x0 ;
len = 0 ;
}
close(pipes[1]) ;
}
void child_proc() {
char buf[32] ;
ssize_t s ;
close(pipes[1]) ;
while ((s = read(pipes[0], buf, 31)) > 0) {
buf[s + 1] = 0x0 ;
printf(">%s\n", buf) ;
}
exit(0) ;
}
int main() {
pid_t child_pid ;
int exit_code ;
if (pipe(pipes) != 0) {
perror("Error") ;
exit(1) ;
}
printf("%d %d\n", pipes[0], pipes[1]) ;
child_pid = fork() ;
if (child_pid == 0) {
child_proc() ;
}
else {
parent_proc() ;
}
wait(&exit_code) ;
exit(0) ;
}
실행 내용
jeongjinhyeog-ui-MacBook-Pro:IPC jeongjinhyeog$ gcc pipe.c -o pipe
jeongjinhyeog-ui-MacBook-Pro:IPC jeongjinhyeog$ ./pipe
3 4
Hello world!
>Hello world!
“Hello world!”는 parent가 “>Hello world!”는 child가 출력한 것이다. 데이터가 잘 전달되었다!!
느낀점
- 왜 파이프가 필요한지는 알 수 있었다.
- 양방향 통신이 궁금하다!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
Subscribe via RSS