양방향 pipe 구현

김도현 KimDohyun·2024년 12월 15일
0

다음 파이프 프로그램을 양방향 통신이 가능하도록 수정하여 제출하시오.
부모프로세스가 보낸 메시지(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 코드를 양방향으로 수정하는 것이다.
양방향 통신 구현은 두 개의 파이프를 생성하고, 각 프로세스에서 필요 없는 파이프의 끝을 닫으면 된다.

개요

pipe란?

파이프는 프로세스 간 통신(IPC, Inter-Process Communication)을 위한 메커니즘 중 하나이며, 파이프를 사용하면 두 개의 프로세스가 데이터를 주고받을 수 있다.

특징

  • 단방향 또는 양방향 통신 가능
  • 데이터를 FIFO(First In First Out) 방식으로 처리
  • 파이프를 통해 한 프로세스는 데이터를 쓰고 다른 프로세스는 그 데이터를 읽음

제약

  • 파이프는 같은 부모-자식 관계의 프로세스 간에서만 사용 가능
  • 기본적으로 단방향 통신만 지원

단방향 통신

단방향 통신은 한쪽 프로세스만 데이터를 보내고 다른 쪽 프로세스만 데이터를 읽는 방식으로, 정보의 흐름이 한 방향으로만 이루어진다.

특징

  • 하나의 파이프만 필요
  • 데이터는 한쪽에서 쓰고 다른 한쪽에서만 읽음

예시

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); // 자식이 부모에게 응답 보냄
}

구현

1. 파이프 개수 증가

// 기존
int pd[2];
pipe(pd);

// 변경
int pd1[2], pd2[2];
pipe(pd1);
pipe(pd2); // 두 번째 파이프 추가

단방향 통신에서는 하나의 파이프만 사용해 데이터를 한 방향으로만 보낼 수 있어서, 양방향 통신을 위해 두 개의 파이프를 추가로 생성했다.

2. 부모 프로세스에서 파이프 끝 처리

// 기존
close(pd[0]); // 부모는 읽기 끝 닫음
  
// 변경
close(pd1[0]); // 부모는 첫 번째 파이프 읽기 끝 닫음
close(pd2[1]); // 부모는 두 번째 파이프 쓰기 끝 닫음

부모가 데이터를 쓰고 자식으로부터 응답을 읽기 위해 첫 번째 파이프의 읽기 끝과 두 번째 파이프의 쓰기 끝을 닫았다.

3. 자식 프로세스에서 파이프 끝 처리

// 기존
close(pd[1]); // 자식은 쓰기 끝 닫음
  
// 변경
close(pd1[1]); // 자식은 첫 번째 파이프 쓰기 끝 닫음
close(pd2[0]); // 자식은 두 번째 파이프 읽기 끝 닫음

자식이 부모 데이터를 읽고 응답을 보내기 위해 첫 번째 파이프의 쓰기 끝과 두 번째 파이프의 읽기 끝을 닫았다.

4. 부모 프로세스의 데이터 송수신 코드

// 기존
write(pd[1], "I am your papa", 16);
  
// 변경
write(pd1[1], "I am your papa", 15); // 부모 → 자식으로 데이터 전송
n = read(pd2[0], line, 128); // 자식 → 부모로부터 데이터 읽음

부모가 데이터를 자식에게 보내고 응답을 받기 위해 첫 번째 파이프에 데이터를 쓰고 두 번째 파이프에서 읽는 코드를 추가했다.

5. 자식 프로세스의 데이터 송수신 코드

// 기존
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;	
}

끝.

0개의 댓글