다음 파이프 프로그램을 양방향 통신이 가능하도록 수정하여 제출하시오.
부모프로세스가 보낸 메시지(I am your papa)가 도착하면 자식프로세스는 부모 프로세스에게 응답메시지(hi)를 보내고 각각의 프로세스는 받은 메시지를 출력하도록 수정하시오.
제공된 코드
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int pd[2], n, i; char line[256];
int main() {
pipe(pd);
printf("pd = [%d, %d]\n", pd[0], pd[1]);
if(fork()) {
printf("parent %d close pd[0]\n", getpid());
close(pd[0]);
while(i++<10) {
printf("parent %d writing to pipe\n", getpid());
n = write(pd[1], "I am your papa", 16);
printf("parent %d wrote %d bytes to pipe\n", getpid(), n);
} printf("parent %d exit\n", getpid());
} else {
printf("child %d close pd[1]\n", getpid());
close(pd[1]);
while(1) {
printf("child %d reading from pipe\n", getpid());
if((n = read(pd[0], line, 128))) {
line[n] = 0;
printf("child read %d bytes from pipe: %s\n", n, line);
} else exit(0);
}
} return 0;
}
여섯 번째 과제는 단방향 pipe 코드를 양방향으로 수정하는 것이다.
양방향 통신 구현은 두 개의 파이프를 생성하고, 각 프로세스에서 필요 없는 파이프의 끝을 닫으면 된다.
파이프는 프로세스 간 통신(IPC, Inter-Process Communication)을 위한 메커니즘 중 하나이며, 파이프를 사용하면 두 개의 프로세스가 데이터를 주고받을 수 있다.
특징
제약
단방향 통신은 한쪽 프로세스만 데이터를 보내고 다른 쪽 프로세스만 데이터를 읽는 방식으로, 정보의 흐름이 한 방향으로만 이루어진다.
특징
예시
pipe(pd); // 단일 파이프 생성
if (fork()) {
close(pd[0]); // 부모는 읽기 끝 닫음
write(pd[1], "data", 4); // 부모가 데이터 씀
}
else {
close(pd[1]); // 자식은 쓰기 끝 닫음
read(pd[0], buffer, 4); // 자식이 데이터 읽음
}
부모 프로세스 → 자식 프로세스로 데이터를 전달하는 코드
양방향 통신은 프로세스 간 데이터를 서로 주고받는 방식으로, 부모 프로세스와 자식 프로세스가 각각 데이터를 읽고 쓰는 작업을 수행한다.
특징
예시
pipe(pd1); // 첫 번째 파이프: 부모 → 자식
pipe(pd2); // 두 번째 파이프: 자식 → 부모
if (fork()) {
close(pd1[0]); close(pd2[1]); // 부모가 읽기 끝과 쓰기 끝 닫음
write(pd1[1], "data", 4); // 부모가 데이터 씀
read(pd2[0], buffer, 4); // 부모가 자식으로부터 응답 읽음
} else {
close(pd1[1]); close(pd2[0]); // 자식이 읽기 끝과 쓰기 끝 닫음
read(pd1[0], buffer, 4); // 자식이 부모로부터 데이터 읽음
write(pd2[1], "ack", 3); // 자식이 부모에게 응답 보냄
}
// 기존
int pd[2];
pipe(pd);
// 변경
int pd1[2], pd2[2];
pipe(pd1);
pipe(pd2); // 두 번째 파이프 추가
단방향 통신에서는 하나의 파이프만 사용해 데이터를 한 방향으로만 보낼 수 있어서, 양방향 통신을 위해 두 개의 파이프를 추가로 생성했다.
// 기존
close(pd[0]); // 부모는 읽기 끝 닫음
// 변경
close(pd1[0]); // 부모는 첫 번째 파이프 읽기 끝 닫음
close(pd2[1]); // 부모는 두 번째 파이프 쓰기 끝 닫음
부모가 데이터를 쓰고 자식으로부터 응답을 읽기 위해 첫 번째 파이프의 읽기 끝과 두 번째 파이프의 쓰기 끝을 닫았다.
// 기존
close(pd[1]); // 자식은 쓰기 끝 닫음
// 변경
close(pd1[1]); // 자식은 첫 번째 파이프 쓰기 끝 닫음
close(pd2[0]); // 자식은 두 번째 파이프 읽기 끝 닫음
자식이 부모 데이터를 읽고 응답을 보내기 위해 첫 번째 파이프의 쓰기 끝과 두 번째 파이프의 읽기 끝을 닫았다.
// 기존
write(pd[1], "I am your papa", 16);
// 변경
write(pd1[1], "I am your papa", 15); // 부모 → 자식으로 데이터 전송
n = read(pd2[0], line, 128); // 자식 → 부모로부터 데이터 읽음
부모가 데이터를 자식에게 보내고 응답을 받기 위해 첫 번째 파이프에 데이터를 쓰고 두 번째 파이프에서 읽는 코드를 추가했다.
// 기존
n = read(pd[0], line, 128);
// 변경
n = read(pd1[0], line, 128); // 부모 → 자식으로부터 데이터 읽기
write(pd2[1], "hi", 3); // 자식 → 부모로 데이터 쓰기
자식이 부모 데이터를 읽고 응답을 보내기 위해 첫 번째 파이프에서 데이터를 읽고 두 번째 파이프에 쓰는 코드를 추가했다.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int pd1[2], pd2[2], n, i;
char line[256];
int main() {
pipe(pd1);
pipe(pd2);
printf("pd1 = [%d, %d]\n", pd1[0], pd1[1]);
printf("pd2 = [%d, %d]\n", pd2[0], pd2[1]);
if (fork()) {
printf("parent %d close pd1[0] and pd2[1]\n", getpid());
close(pd1[0]);
close(pd2[1]);
while (i++<10) {
printf("parent %d writing to pipe\n", getpid());
n = write(pd1[1], "I am your papa", 15);
printf("parent %d wrote %d bytes to pipe\n", getpid(), n);
printf("parent %d reading from pipe\n", getpid());
n = read(pd2[0], line, 128);
if (n>0) {
line[n] = 0;
printf("parent read %d bytes from pipe: %s\n", n, line);
}
}
printf("parent %d exit\n", getpid());
close(pd1[1]);
close(pd2[0]);
}
else {
printf("child %d close pd1[1] and pd2[0]\n", getpid());
close(pd1[1]);
close(pd2[0]);
while(1) {
printf("child %d reading from pipe\n", getpid());
n = read(pd1[0], line, 128);
if (n>0) {
line[n] = 0;
printf("child read %d bytes from pipe: %s\n", n, line);
printf("child %d writing to pipe\n", getpid());
n = write(pd2[1], "hi", 3);
printf("child wrote %d bytes to pipe\n", n);
}
else {
break;
}
}
printf("child %d exit\n", getpid());
close(pd1[0]);
close(pd2[1]);
}
return 0;
}
끝.