Linux System Linux System Programming Programming Lecture #8 – 파파파 (Pipe)
Jan 17, 2016
Linux System Linux System ProgrammingProgramming
Lecture #8 – 파이프 (Pipe)
Linux System Programming 2
파이프 (Pipe) (1)파이프 (Pipe) (1)
파이프 (Pipe) 정의 : 하나의 프로세스를 다른 프로세스에 연결시켜 주는 일방 통행의
통신 채널 리눅스의 파일 개념을 일반화한 프로세스 통신 객체
파일 입출력 시스템 호출을 통해 접근이 가능하나의 프로세스가 write 시스템 호출을 이용하여 데이터를 파이프를 통해 전송하면 , 다른 프로세스가 read 시스템 호출을 이용하여 데이터를 읽어 들일 수 있다
프로세스들 사이에 데이터를 FIFO 방식으로 전달할 수 있게 하며 , 프로세스 수행의 동기화를 지원
일잔적으로 파일 시스템을 이용하여 파이프를 구현
Linux System Programming 3
파이프 (Pipe) (2)파이프 (Pipe) (2)
파이프 (Pipe) 정의 : 정규 파일과 파이프의 비교 :
정규 파일 파이프
접근 권한 접근허가비트를 이용하여 무관한 프로세스들이 접근 가능
연관된 프로세스만이 접근 가능( 부모 - 자식 프로세스 )
수명프로세스의 수명과 무관파일 내의 데이터는 non-volatile
프로세스 수명과 동일파일 내의 데이터는 volatile
용량 고정된 용량을 초과할 수 없음연속적인 바잍 스트림이므로 무제한의 정보 전달이 가능일시적인 입출력 데이터 양은 적다
동기화 별도의 입출력 동기화가 필요 입출력 동기화를 지원
Linux System Programming 4
파이프 (Pipe) (3)파이프 (Pipe) (3)
파이프 (Pipe) 종류 : 파이프의 종류
명명된 파이프 (Named Pipe) 비명명된 파이프 (Unnamed Pipe) – 보통 ‘파이프’라고 함
명명된 파이프와 비명명된 파이프의 비교
명명된 파이프 비명명된 파이프
이름 (ID) 접근을 위한 별도의 이름 가짐 이름을 가지지 않음
생성 및 접근 방법
open() 시스템 호출을 통해 생성접근을 위한 시스템 호출은 동일
pipe() 시스템 호출을 통해 생성접근을 위한 시스템 호출은 동일
접근 권한 이름을 통해 모든 프로세스가 접근 가능
연관된 프로세스 , 즉 부모와 자식 관계를 갖는 프로세스만 접근
수명영구적으로 존재 가능정규 파일과 같은 방법으로 조작
close() 시스템 호출에 의해 소멸
Linux System Programming 5
파이프 (Pipe) (3)파이프 (Pipe) (3)
파이프 (Pipe) 접근 권한 : 명명된 파이프의 접근 권한
접근 허가 모드 설정을 통해 제한 비명명된 파이프의 접근 권한
프로세스 A
프로세스 B 프로세스 C
프로세스 D 프로세스 E
파이프 생성
파이프 접근 가능
Linux System Programming 6
Pipe 시스템 호출 (1)Pipe 시스템 호출 (1)
Pipe 시스템 호출 : 비명명된 파이프를 생성
Linux System Programming 7
Pipe 시스템 호출 (2)Pipe 시스템 호출 (2)
비명명된 파이프 접근 시스템 호출 :
Linux System Programming 8
Pipe 시스템 호출 (3)Pipe 시스템 호출 (3)
리눅스 시스템에서의 파이프 구현 파일시스템에서 임시 파일을 생성하여 파이프를 지원
Linux System Programming 9
Pipe 시스템 호출 (4)Pipe 시스템 호출 (4)
예제 8-1 비명명된 파이프를 생성하여 부모 프로세스에서 메시지를
보내고 자식 프로세스에서 메시지를 출력하는 프로그램
#define MSGSIZE 20
main(argc,argv)int argc;char *argv[];{
int fd[2], pid, pipe(), fork();static char msgout[MSGSIZE] = "Hello, world\n";static char msgin[MSGSIZE];
if(pipe(fd) == -1) {perror(argv[0]);exit(1);
}
Linux System Programming 10
Pipe 시스템 호출 (5)Pipe 시스템 호출 (5)
if((pid = fork()) > 0) { /* parent */write(fd[1], msgout, MSGSIZE);
}else if(pid == 0) { /* child */
read(fd[0], msgin, MSGSIZE);puts(msgin);
}else { /* cannot fork */
perror(argv[0]);exit(2);
}exit(0);
}
Linux System Programming 11
Pipe 시스템 호출 (6)Pipe 시스템 호출 (6)
예제 8-2 두 개의 자식 프로세스를 파이프를 생성하여 통신하는 프로그램
#include <stdio.h>char text[80];
main(int argc, char *argv[]){
int fd[2], pipe(), fork(), wait();
if(pipe(fd) == -1) {perror(argv[0]);exit(1);
}if(fork() == 0) { /* first child */
close(1);dup(fd[1]); /* redirection std output */close(fd[0]); close(fd[1]);printf("who display sorted\n");fflush(stdout);execl("/usr/bin/who","who",(char *) 0);exit(127);
}
Linux System Programming 12
Pipe 시스템 호출 (7)Pipe 시스템 호출 (7)
if(fork() == 0) { /* second child */close(0);dup(fd[0]); /* redirection std output */close(fd[0]); close(fd[1]);read_to_nl(text);printf("Heading: %s\n",text);fflush(stdout);execl("/bin/sort","sort",(char *) 0);exit(127);
}close(fd[0]); close(fd[1]);while(wait((int *) 0) != -1) ; /* null */exit(0);
}
read_to_nl(input)char *input;{
while(1) {read(0, input, 1);if(*input == '\n') break;else input++;
}}
Linux System Programming 13
파이프 라이브러리 함수 (1)파이프 라이브러리 함수 (1) 파이프 라이브러리 함수 : popen(), pclose()
비명명된 파이프를 생성하고 닫는 라이브러리 함수 정규파일을 열고 닫는 fopen()/fclose() 와 유사
Linux System Programming 14
파이프 라이브러리 함수 (2)파이프 라이브러리 함수 (2) 파이프 라이브러리 함수의 실행 과정
popen() 함수 – fork()/exec()/pipe()/dup() 을 이용하여 구현 pclose() 함수 – wait()/close() 를 이용하여 구현
Linux System Programming 15
파이프 라이브러리 함수 (3)파이프 라이브러리 함수 (3)
예제 8-3 파이프 표준 라이브러리 함수 popen()/pclose() 를 사용하여
리눅스 명령어 “ who | sort” 를 실행하는 프로그램
#include <stdio.h>
main(){
FILE *fpin, *fpout;char line[BUFSIZ];
fpin = popen("who","r");fpout = popen("sort","w");
while(fgets(line, BUFSIZ, fpin) != (char *) NULL) fputs(line,fpout);
pclose(fpin);pclose(fpout);
}
Linux System Programming 16
명명된 파이프 (Named Pipe) (1)명명된 파이프 (Named Pipe) (1)
명명된 파이프 (Named Pipe) 비명명된 파이프의 문제점
첫째 , 파이프는 부무와 자식 프로세스와 같이 연관된 프로세스만이 접근 가능하다
둘째 , 파이프는 영구히 존재할 수 없다 – 파이프는 필요할 때에 만들어지고 파이프와 관계된 프로세스가 종료할 때에 소멸한다
시스템 전체에 대해 서비스를 제공하는 서버 (server) 를 개발하고자 할 때에 문제가 발생
명명된 파이프 또는 FIFO 비명명된 파이프와 같이 프로세스간의 통신 및 동기화 기능 지원 파일 시스템에서 특수 파일 형태로 영구 존재 리눅스 파일 이름을 부여하고 접근 허가 설정을 통해 모든
프로세스가 접근 가능 비명명된 파이프와 동일한 방법으로 시스템 호출을 사용하여 접근
Linux System Programming 17
명명된 파이프 (Named Pipe) (2)명명된 파이프 (Named Pipe) (2)
명명된 파이프 (Named Pipe) 생성 : mknod 시스템 호출
Linux System Programming 18
명명된 파이프 (Named Pipe) (3)명명된 파이프 (Named Pipe) (3)
명명된 파이프 (Named Pipe) 생성 : mknod 시스템 호출의 매개 변수
생성되는 파일 유형 : 파일 생성 허가 모드 :
Linux System Programming 19
명명된 파이프 (Named Pipe) (4)명명된 파이프 (Named Pipe) (4)
예제 8-4 다음 그림과 같은 기능을 지원하는 파일 서버 /클라이언트 (ser
ver/client) 프로그램
Linux System Programming 20
명명된 파이프 (Named Pipe) (5)명명된 파이프 (Named Pipe) (5)
// file name: ex8-4.h//
struct message {char privfifo[15]; /* name of private named pipe */char filename[100]; /* name of file */
};
#define PUBLIC "Public"#define LINESIZE 512#define NUMTRIES 3
Linux System Programming 21
명명된 파이프 (Named Pipe) (6)명명된 파이프 (Named Pipe) (6)
// file name: ex8-4a.c//#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include "ex8-4.h"
main(argc,argv)int argc;char *argv[];{
struct message msg;int n, getpid();int fdpub, fdpriv, open();char line[LINESIZE];
sprintf(msg.privfifo,"Fifo%d",getpid());if(mknod(msg.privfifo, S_IFIFO| 0666, 0) == -1) {
perror(msg.privfifo);exit(1);
}
Linux System Programming 22
명명된 파이프 (Named Pipe) (7)명명된 파이프 (Named Pipe) (7)
if((fdpub = open(PUBLIC, O_WRONLY)) == -1) {perror(PUBLIC);exit(2);
}strcpy(msg.filename, argv[1]);write(fdpub, (char *) &msg, sizeof(msg));
if((fdpriv = open(msg.privfifo, O_RDONLY)) ==-1) {perror(msg.privfifo);exit(3);
}while((n=read(fdpriv, line, LINESIZE)) > 0)
write(1,line,n);close(fdpriv);unlink(msg.privfifo);exit(0);
}
Linux System Programming 23
명명된 파이프 (Named Pipe) (8)명명된 파이프 (Named Pipe) (8)
// file name: ex8-4b.c//#include <fcntl.h>#include "ex8-4.h"
main(argc,argv)int argc;char argv;{
int fdpub, fdpriv, fd, open();struct message msg;int n;char line[LINESIZE];
loop: /* forver */if((fdpub = open(PUBLIC, O_RDONLY)) == -1) {
perror(PUBLIC);exit(1);
}
Linux System Programming 24
명명된 파이프 (Named Pipe) (9)명명된 파이프 (Named Pipe) (9)
while(read(fdpub, (char *) &msg,sizeof(msg)) >0) {if((fd=open(msg.filename,O_RDONLY)) == -1) {
perror(msg.filename);break;
}if((fdpriv=open(msg.privfifo,O_WRONLY)) == -1) {
perror(msg.privfifo);break;
}while((n=read(fd,line,LINESIZE)) > 0)
write(fdpriv, line, n);close(fd);close(fdpriv);
}close(fdpub);goto loop;
}
Linux System Programming 25
예제 프로그램 (1)예제 프로그램 (1)
예제 8-6: 파이프를 통하여 통신하는 두 개의 프로세스를 생성하고 ,
부모 프로세스는 소문자로 된 문장을 파이프를 통해 전송하고 , 자식 프로세스는 파이프에서 데이터를 읽어 대문자로 변환하여 출력하는 프로그램
#include <ctype.h>
main(int argc, char *argv[]){ int pid, fd[2]; static char *line[3] = { "Here are 3 lines of test.\n", "You will see all lower case\n", "made to upper!!\n" }; char input[1000]; int i, rtn;
if(pipe(fd) == -1) { perror(argv[0]); exit(1); }
Linux System Programming 26
예제 프로그램 (2)예제 프로그램 (2)
if((pid = fork()) > 0) { /* parent */ close(fd[0]); for(i=0; i<3 ; i++) write(fd[1],line[i],strlen(line[i])); close(fd[1]); } else if(pid == 0) { /* child */ close(fd[1]); while((rtn = read(fd[0], input, 1000)) > 0) { for(i=0; i<rtn; i++) if(islower(input[i])) input[i] = toupper(input[i]); write(1,input, rtn); } close(fd[0]); } else { /* cannot fork */ perror(argv[0]); exit(2); } exit(0);}
Linux System Programming 27
예제 프로그램 (3)예제 프로그램 (3)
예제 8-8: 리눅스의 wc 명령어를 이용하여 파일에 포함되어 있는 공백
라인을 계수하여 출력하는 프로그램 파이프 표준 라이브러리 함수 (popen, pclose) 를 이용하여
작성#include <stdio.h>#define TRUE 1#define FALSE 0
main(int argc, char *argv[]){ FILE *fpin, *fpout; char line[BUFSIZ]; int strlen(); if((fpin = fopen(argv[1], "r")) == (FILE *) NULL) { perror(argv[0]); exit(1); }
Linux System Programming 28
예제 프로그램 (4)예제 프로그램 (4)
fpout = popen("wc -l","w");
while (fgets(line, BUFSIZ, fpin) != (char *) NULL) if(line[0] == '\n') fputs(line,fpout);
fclose(fpin); pclose(fpout);}
Linux System Programming 29
예제 프로그램 (5)예제 프로그램 (5)
예제 8-9: 미니 셀 (mini-shell) 프로그램 ex7-16.c 를 파이프 라인
기능이 가능하도록 수정하여라 교재의 프로그램 ‘ ex8-9.c’ 를 참조
Linux System Programming 30
예제 프로그램 (6)예제 프로그램 (6)
예제 8-10: 숫자 맞추기 게임 프로그램 :
1. 두 개의 프로그램은 명명된 파이프를 통해 통신한다2. 첫번째 프로그램은 명명된 파이프 (FIFO) 를 생성하고 임의의
숫자를 난수로 발생한다3. 첫번째 프로그램은 두번째 프로그램은에서 FIFO 를 통하여 전송한
숫자가 정답과 비교하여 크면 ‘ H’, 작으면 ‘ L’, 같으면 ‘ E’이라는 메시지를 FIFO 를 통해 두번째 프로그램에 전송한다
4. 두번째 프로그램은 경기자가 추측하여 응답한 숫자를 FIFO 를 통하여 첫번째 프로그램으로 전송하고 , 그값이 크다 (H), 작다(L), 같다 (E) 와 같은 응답을 받아 화면에 출력하여 숫자를 맞출 때까지 반복한다
5. 두 개의 파이프를 생성하여 질문과 응답을 전달하는 통신 채널로 사용한다
Linux System Programming 31
예제 프로그램 (7)예제 프로그램 (7)
// file name: ex8-10a.c//#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define GUESSFIFO "Guessfifo"#define RESPNSFIFO "Respnsfifo"
main(argc,argv)int argc;char *argv[];{ int number, guess, rand(); int fdguess, fdresp, open();
if(mknod(GUESSFIFO, S_IFIFO | 0666, 0) == -1) { perror(GUESSFIFO); exit(1); } if(mknod(RESPNSFIFO, S_IFIFO | 0666, 0) == -1) { perror(RESPNSFIFO); exit(2); }
Linux System Programming 32
예제 프로그램 (8)예제 프로그램 (8)
if((fdguess = open(GUESSFIFO, O_RDONLY)) == -1) { perror(GUESSFIFO); exit(3); } if((fdresp = open(RESPNSFIFO, O_WRONLY)) == -1) { perror(RESPNSFIFO); exit(4); } number = rand() % 1000;
while(read(fdguess, (char *) &guess, sizeof(guess)) > 0) { if(guess > number) write(fdresp, "H", 1); else if(guess < number) write(fdresp, "L", 1); else write(fdresp, "E", 1); } close(fdguess); close(fdresp); unlink(GUESSFIFO); unlink(RESPNSFIFO); exit(0);}
Linux System Programming 33
예제 프로그램 (9)예제 프로그램 (9)
// file name: ex8-10b.c//
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define GUESSFIFO "Guessfifo"#define RESPNSFIFO "Respnsfifo"
main(int argc, char *argv[]){ int higuess, loguess, guess; int fdguess, fdresp, open(); char response;
if((fdguess = open(GUESSFIFO, O_WRONLY)) == -1) { perror(GUESSFIFO); exit(1); } if((fdresp = open(RESPNSFIFO, O_RDONLY)) == -1) { perror(RESPNSFIFO); exit(2); }
Linux System Programming 34
예제 프로그램 (10)예제 프로그램 (10)
loguess = 0; higuess = 1000; guess = 500; write(fdguess, (char *) &guess, sizeof(guess)); while(read(fdresp, &response, 1) > 0) { if(response == 'H') { printf("%d is too high\n",guess); higuess = guess; guess = (higuess + loguess) / 2; } else if(response == 'L') { printf("%d is too low\n",guess); loguess = guess; guess = (higuess + loguess) / 2; } else { printf("%d is correct\n",guess); break; } write(fdguess, (char *) &guess, sizeof(guess)); } close(fdguess); close(fdresp); exit(0);}