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