
cat test.c | more_
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
int pipe(int pipefd[2]);
mknod 파일명 p
mkfifo [-m mode] ...NAME...
int mknod(const char *pathname, mode_t mode, dev_t dev);
int mkfifo(const char *pathname, mode_t mode);
파이프를 만드는 가장 간단한 방법은 popen() 함수를 사용하는 것
#include<stdio.h>
FILE *popen(const char *command, const char *type);
* command : 셀 명령
* type : "r" 또는 "w"
execl("/bin/sh", "sh", "-c", command, (char *)0);
#include<stdio.h>
int pclose(FILE *stream);
* stream : popen 함수에서 리턴한 파일 포인터
* return : 자식 프로세스의 종료 상태(exit status) / 실패 시 -1
popen() 함수를 쓰기 전용 모드로 사용해 파이프를 생성해보자
#include<stdlib.h>
#include<stdio.h>
int main() {
FILE *fp;
int a;
fp = popen("wc -l", "w");
if (fp == NULL) {
fprintf(stderr, "popen failed\n");
exit(1);
}
for (a = 0; a < 100; a++)
fprintf(fp, "test line\n");
pclose(fp);
}
결과 값 : 100
이번에는 popen() 함수를 읽기 전용 모드로 사용해 파이프를 생성해보자. 자식 프로세스가 파이프에 기록한 데이터를 부모 프로세스가 읽어서 처리한다.
#include<stdlib.h>
#include<stdio.h>
int main() {
FILE *fp;
char buf[256];
fp = popen("date", "r");
if(fp == NULL) {
fprintf(stderr, "popen failed\n");
exit(1);
}
if (fgets(buf, sizeof(buf), fp) == NULL) {
fprintf(stderr, "No data from pipe!\n");
exit(1);
}
printf("line : %s\n", buf);
pclose(fp);
}
결과 값 : line : 현재 날짜 및 시간 정보
#include<unistd.h>
int pipe(int pipefd[2]);
pipe() 함수로 생성한 파이프로 통신하는 과정을 살펴보자
이 과정을 단계적으로 살펴보자
1. pipe() 함수를 호출해 파이프에 사용할 파일 기술자를 얻음. 파이프도 파일의 일종이므로 파일(파이프)을 읽고 쓸 수 있는 파일 기술자가 필요한데, 이를 pipe() 함수가 생성해줌.
2. fork() 함수를 수행해 자식 프로세스를 생성함. 이때 pipe() 함수에서 생성한 파일 기술자도 자식 프로세스로 복사됨. 같은 파일 기술자를 부모 프로세스와 자식 프로세스가 모두 가지고 있음
3. 파이프는 단방향 통신이므로 통신 방향을 결정함. 예를 들어, 부모 프로세스는 쓰기를 하고 자식 프로세스는 읽기를 해야한다고 했을 때, 각각의 파일 기술자에서 쓰지 않는 읽기 또는 쓰기의 파일 기술자를 닫아야 함
만약! 파이프의 쓰기 부분이 닫혀 있다면 파이프에서 읽으려고 할 때 0이나 EOF가 리턴함
파이프의 읽기 부분이 닫혀 있다면 파이프에 쓰려고 할 때 SIGPIPE 시그널이 발생함
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int fd[2]; // 파이프 파일 디스크립터를 저장할 배열
pid_t pid; // 프로세스 ID를 저장할 변수
char buf[257]; // 메시지를 저장할 버퍼
int len, status;
// 파이프 생성
if (pipe(fd) == -1) {
perror("pipe"); // 에러 메시지 출력
exit(1); // 프로그램 종료
}
// 자식 프로세스 생성
switch (pid = fork()) {
case -1 : // fork 실패 시
perror("fork"); // 에러 메시지 출력
exit(1); // 프로그램 종료
break;
case 0 : /* 자식 프로세스 */
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]); // 읽기용 파이프 종료
write(fd[1], "Test Message\n", 14); // 쓰기용 파이프에 메시지 쓰기
close(fd[1]); // 쓰기용 파이프 종료
waitpid(pid, &status, 0); // 자식 프로세스가 종료될 때까지 대기
break;
}
}
결과 값 : Child Process: Test Message
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int fd[2]; // 파이프 파일 디스크립터를 저장할 배열
pid_t pid; // 프로세스 ID를 저장할 변수
// 파이프 생성
if (pipe(fd) == -1) {
perror("pipe"); // 에러 메시지 출력
exit(1); // 프로그램 종료
}
// 자식 프로세스 생성
switch (pid = fork()) {
case -1 : // fork 실패 시
perror("fork"); // 에러 메시지 출력
exit(1); // 프로그램 종료
break;
case 0 : /* 자식 프로세스 */
close(fd[1]); // 쓰기용 파이프 종료
if (fd[0] != 0) {
dup2(fd[0], 0); // 읽기용 파이프를 표준 입력으로 복제
close(fd[0]); // 복제된 읽기용 파이프 종료
}
execlp("grep", "grep", "ssh", (char *)NULL); // "ssh"를 포함한 라인만 필터링하는 grep 명령 실행
exit(1); // 프로그램 종료
break;
default : /* 부모 프로세스 */
close(fd[0]); // 읽기용 파이프 종료
if (fd[1] != 1) {
dup2(fd[1], 1); // 쓰기용 파이프를 표준 출력으로 복제
close(fd[1]); // 복제된 쓰기용 파이프 종료
}
execlp("ps", "ps", "-ef", (char *)NULL); // 모든 프로세스의 정보를 출력하는 ps 명령 실행
wait(NULL); // 자식 프로세스가 종료될 때까지 대기
break;
}
}
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
int fd1[2], fd2[2]; // 양방향 통신을 위한 두 개의 파이프 파일 디스크립터 배열
pid_t pid; // 프로세스 ID를 저장할 변수
char buf[257]; // 메시지를 저장할 버퍼
int len, status;
// 첫 번째 파이프 생성
if (pipe(fd1) == -1) {
perror("pipe"); // 에러 메시지 출력
exit(1); // 프로그램 종료
}
// 두 번째 파이프 생성
if (pipe(fd2) == -1) {
perror("pipe"); // 에러 메시지 출력
exit(1); // 프로그램 종료
}
// 자식 프로세스 생성
switch (pid = fork()) {
case -1 : // fork 실패 시
perror("fork"); // 에러 메시지 출력
exit(1); // 프로그램 종료
break;
case 0 : /* 자식 프로세스 */
close(fd1[1]); // 첫 번째 파이프의 쓰기용 종료
close(fd2[0]); // 두 번째 파이프의 읽기용 종료
len = read(fd1[0], buf, 256); // 첫 번째 파이프에서 메시지 읽기
write(1, "Child Process:", 15); // 자식 프로세스 메시지 출력
write(1, buf, len); // 읽은 메시지 출력
strcpy(buf, "Good\n"); // 버퍼에 "Good\n" 문자열 복사
write(fd2[1], buf, strlen(buf)); // 두 번째 파이프에 메시지 쓰기
break;
default : /* 부모 프로세스 */
close(fd1[0]); // 첫 번째 파이프의 읽기용 종료
close(fd2[1]); // 두 번째 파이프의 쓰기용 종료
write(fd1[1], "Hello\n", 6); // 첫 번째 파이프에 메시지 쓰기
len = read(fd2[0], buf, 256); // 두 번째 파이프에서 메시지 읽기
write(1, "Parent Process:", 15); // 부모 프로세스 메시지 출력
write(1, buf, len); // 읽은 메시지 출력
waitpid(pid, &status, 0); // 자식 프로세스가 종료될 때까지 대기
break;
}
}
결과 값 : username 1234 0.0 0.0 1234 5678 pts/0 Ss+ Dec04 0:00 ssh example@example.com