파이프 IT CookBook, 유닉스시스템프로그래밍
학습목표 파이프를이용한 IPC 기법을이해한다. 이름없는파이프를이용해통신프로그램을작성할수있다. 이름있는파이프를이용해통신프로그램을작성할수있다. 2/20
목차 파이프의개념 이름없는파이프만들기 복잡한파이프생성 양방향파이프활용 이름있는파이프만들기 3/20
파이프의개념 파이프 두프로세스간에통신할수있도록해주는특수파일 그냥파이프라고하면일반적으로이름없는파이프를의미 이름없는파이프는부모-자식프로세스간에통신할수있도록해줌 파이프는기본적으로단방향 간단한파이프생성 파이프생성 : popen(3) #include <stdio.h> FILE *popen(const char *command, const char *mode); command : 쉘명령 mode : r ( 읽기전용파이프 ) 또는 w ( 쓰기전용파이프 ) 파이프닫기 : pclose(3) #include <stdio.h> int pclose(file *stream); 4/20
[ 예제 9-1] popen 함수사용하기 ( 쓰기전용 ) ex9_1.c... 04 int main(void) { 05 FILE *fp; 06 int a; 07 08 fp = popen("wc -l", "w"); 09 if (fp == NULL) { 10 fprintf(stderr, "popen failed\n"); 11 exit(1); 12 } 13 14 for (a = 0; a < 100; a++) 15 fprintf(fp, "test line\n"); 16 17 pclose(fp); 18 19 return 0; 20 } w 모드로파이프생성자식프로세스는 wc l 명령수행 자식프로세스로출력 결과는무엇일까? 5/20
[ 예제 9-2] popen 함수사용하기 ( 읽기전용 ) ex9_2.c... 04 int main(void) { 05 FILE *fp; 06 char buf[256]; 07 08 fp = popen("date", "r"); 09 if (fp == NULL) { 10 fprintf(stderr, "popen failed\n"); 11 exit(1); 12 } 13 14 if (fgets(buf, sizeof(buf), fp) == NULL) { 15 fprintf(stderr, "No data from pipe!\n"); 16 exit(1); 17 } 18 19 printf("line : %s\n", buf); 20 pclose(fp); 21 22 return 0; 23 } # ex9_2.out 자식프로세스는 date 명령실행 읽기모드로파이프생성 파이프에서데이터읽기 line : 2010 년 2 월 5 일금요일오후 11 시 20 분 40 초 6/20
복잡한파이프생성 [1] 파이프만들기 : pipe(2) #include <unistd.h> int pipe(int fildes[2]); 파이프로사용할파일기술자 2개를인자로지정 fildes[0] 는읽기, fildes[1] 은쓰기용파일기술자 pipe 함수로통신과정 1. piep 함수를호출하여파이프로사용할파일기술자생성 7/20
복잡한파이프생성 [2] 2. fork 함수로자식프로세스생성. pipe 도자식프로세스로복사됨 3. 통신방향결정 ( 파이프는기본적으로단방향 ) 8/20
[ 예제 9-3] pipe 함수사용하기 (1) ex9_3.c... 06 int main(void) { 07 int fd[2]; 08 pid_t pid; 09 char buf[257]; 10 int len, status; 11 12 if (pipe(fd) == -1) { 13 perror("pipe"); 14 exit(1); 15 } 16 17 switch (pid = fork()) { 18 case -1 : 19 perror("fork"); 20 exit(1); 21 break; 파이프생성 fork 로자식프로세스생성 9/20
[ 예제 9-3] pipe 함수사용하기 (1) ex9_3.c 22 case 0 : /* child */ 23 close(fd[1]); 24 write(1, "Child Process:", 15); 25 파이프에서 len = read(fd[0], buf, 256); 26 읽기 write(1, buf, len); 27 close(fd[0]); 28 break; 부모프로세스는파이프에 29 default : 쓸것이므로읽기용파일기 30 close(fd[0]); 술자 (fd[0]) 를닫는다. 31 buf[0] = '\0'; 32 write(fd[1], "Test Message\n", 14); 33 close(fd[1]); 34 waitpid(pid, &status, 0); 35 break; 36 } 37 38 return 0; 39 } 자식프로세스는파이프에서읽을것이므로쓰기용파일기술자 (fd[1]) 를닫는다. 파이프에텍스트를출력 # ex9_3.out Child Process:Test Message 10/20
[ 예제 9-4] pipe 함수사용하기 (2) ex9_4.c ps ef grep telnet 동작구현... 06 int main(void) { 07 int fd[2]; 08 pid_t pid; 09 10 if (pipe(fd) == -1) { 11 perror("pipe"); 파이프생성 12 exit(1); 13 } 14 15 switch (pid = fork()) { 16 case -1 : 17 perror("fork"); 18 exit(1); 19 break; 20 case 0 : /* child */ 21 close(fd[1]); 22 if (fd[0]!= 0) { fd[0] 에 0번 ( 표준입력 ) 을복사 23 dup2(fd[0], 0); 자식프로세스는파이프 24 close(fd[0]); 입력으로 0번사용 25 } 11/20
[ 예제 9-4] pipe 함수사용하기 (2) ex9_4.c 26 execlp("grep", "grep", "telnet", (char *)NULL); 27 exit(1); 28 break; grep telnet 명령실행 29 default : 30 close(fd[0]); 31 if (fd[1]!= 1) { fd[1] 에 1번 ( 표준출력 ) 을복사 32 dup2(fd[1], 1); 부모로세스는파이프 33 close(fd[1]); 출력으로 1번사용 34 } 35 execlp("ps", "ps", "-ef", (char *)NULL); 36 wait(null); 37 break; 38 } 39 40 return 0; 41 } ps -ef 명령실행 # ex9_4.out root 1568 342 0 2ਘ 08? 0:00 /usr/sbin/in.telnetd root 1576 342 0 2ਘ 08? 0:00 /usr/sbin/in.telnetd root 2763 342 0 2ਘ 10? 0:00 /usr/sbin/in.telnetd root 3782 3781 0 09:40:12 pts/3 0:00 grep telnet 12/20
양방향파이프의활용 양방향통신 파이프는기본적으로단방향이므로양방향통신을위해서는파이프를 2 개생성한다. 13/20
[ 예제 9-5] 양방향통신하기 ex9_5.c... 07 int main(void) { 08 int fd1[2], fd2[2]; 09 pid_t pid; 10 char buf[257]; 11 int len, status; 12 13 if (pipe(fd1) == -1) { 14 perror("pipe"); 15 exit(1); 16 } 17 18 if (pipe(fd2) == -1) { 19 perror("pipe"); 20 exit(1); 21 } 22 23 switch (pid = fork()) { 24 case -1 : 25 perror("fork"); 26 exit(1); 27 break; 파이프 2 개를생성하기위해배열 2 개선언 파이프 2 개생성 14/20
[ 예제 9-5] 양방향통신하기 ex9_5.c 28 case 0 : /* child */ 29 close(fd1[1]); 30 close(fd2[0]); 31 write(1, "Child Process:", 15); 32 len = read(fd1[0], buf, 256); 33 write(1, buf, len); 34 35 strcpy(buf, "Good\n"); 36 write(fd2[1], buf, strlen(buf)); 37 break; 38 default : 39 close(fd1[0]); 40 close(fd2[1]); 41 buf[0] = '\0'; 42 write(fd1[1], "Hello\n", 6); 43 44 write(1, "Parent Process:", 15); 45 len = read(fd2[0], buf, 256); 46 write(1, buf, len); 47 waitpid(pid, &status, 0); 48 break; 49 } 50 51 return 0; 52 } 자식프로세스 -fd1[0] 으로읽기 -fd2[1] 로쓰기 부모프로세스 -fd1[1] 로쓰기 -fd2[0] 으로읽기 # ex9_5.out Child Process:Hello Parent Process:Good 15/20
이름있는파이프 [1] 이름있는파이프 부모 - 자식간이아닌독립적인프로세스간에통신하기위해서는이름있는파이프사용 이름있는파이프는 FIFO 라고도함 FIFO 로사용할특수파일을명령이나함수로먼저생성해야함 명령으로 FIFO 파일생성 mknod 명령 mknod 파일명 p # mknod HAN_FIFO p # ls -l HAN_FIFO prw-r--r-- 1 root other 0 2월 13일 12:21 HAN_FIFO # ls -F HAN_FIFO FIFO 표시 mkfifo 명령 /usr/bin/mkfifo [-m mode] path # mkfifo -m 0644 BIT_FIFO # ls -l BIT_FIFO prw-r--r-- 1 root other 0 2 월 13 일 12:28 BIT_FIFO 16/20
이름있는파이프 [2] 함수로특수파일생성 특수파일생성 : mknod(2) #include <sys/stat.h> int mknod(const char *path, mode_t mode, dev_t dev); mode : 생성할특수파일의종류지정 S_IFIFO : FIFO 특수파일 S_IFCHAR : 문자장치특수파일 S_IFDIR : 디렉토리 S_IFDIR : 블록장치특수파일 S_IFREG : 일반파일 FIFO 파일생성 : mkfifo(3) #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *path, mode_t mode); mode : 접근권한지정 17/20
[ 예제 9-7] FIFO 로데이터주고받기 - 서버프로그램 ex9_7s.c... 08 int main(void) { 09 int pd, n; 10 char msg[] = "Hello, FIFO"; 11 12 printf("server =====\n"); 13 14 if (mkfifo("./han-fifo", 0666) == -1) { 15 perror("mkfifo"); 16 exit(1); 17 } 18 19 if ((pd = open("./han-fifo", O_WRONLY)) == -1) { 20 perror("open"); 21 exit(1); 22 } 23 24 printf("to Client : %s\n", msg); 25 26 n = write(pd, msg, strlen(msg)+1); 27 if (n == -1) { 28 perror("write"); 29 exit(1); 30 } 31 close(pd); 32 33 return 0; 34 } FIFO 파일생성 FIFO 파일쓰기모드로열기 FIFO 파일에문자열출력 18/20
[ 예제 9-7] FIFO 로데이터주고받기 클라이언트프로그램 ex9_7c.c... 08 int main(void) { 07 int pd, n; 08 char inmsg[80]; 09 10 if ((pd = open("./han-fifo", O_RDONLY)) == -1) { 11 perror("open"); 12 exit(1); 13 } 14 15 printf("client =====\n"); 16 write(1, "From Server :", 13); 17 18 while ((n=read(pd, inmsg, 80)) > 0) 19 write(1, inmsg, n); 20 21 if (n == -1) { 22 perror("read"); 23 exit(1); 24 } 25 26 write(1, "\n", 1); 27 close(pd); 28 29 return 0; 30 } 서버측에서생성한 FIFO 파일열기 서버가보낸데이터읽기 # ex9_7s.out Server ===== To Client : Hello, FIFO # # ex9_7c.out Client ===== From Server :Hello, FIFO # 19/20
IT CookBook, 유닉스시스템프로그래밍