카테고리 없음

[Network Programming] 프로세스간 통신

hw-ani 2023. 5. 29. 02:59

(시스템 프로그래밍때 했으니.. 간단하게...)

 

process간 통신(IPC)는 쉽게 되는게 아니다. 왜냐하면 모든 Process는 독립적인 메모리 공간을 사용하도록 OS에서 보장해주기 때문이다. 일반적인 방법으론 서로 메모리에 접근할 수 없으니, OS에서 별도로 메모리 공간을 마련해줘야 한다.

IPC를 위해 OS에서 제공해주는 놈들로는 shared memory도 있고, message queue도 있고, pipe도 있다.(더 있을라나?)

여기선 pipe에 대해 배운다.

 

DISK를 왔다갔다하며 IPC를 수행하기엔 소모가 너무 크다...
pipe는 보통 fork()로 프로세스를 나눠서 소통할 때 사용하고, MQ나 SM은 정해진 key 값으로 해당 공간을 얻을 수 있기때문에 child-parent 관계가 아닌 아예 다른 process간에도 사용하기 좋다.
대신 shared memory 나 message queue는 보통 semaphore 같은 걸로 race condition이 발생하지 않도록 보호를 해줘야한다. pipe도 복잡한 시나리오에선 그래야 할 수도 있지만,, 보통은 그렇단 것.

 

 

 

pipe

#include <unistd.h>

int pipe(int fd[2]);

pipe라는 운영체제가 제공해주는 공유 메모리를 얻어오는 함수이다.

인자로 준 int 배열에는 OS가 만든 공유 메모리에 접근할 수 있는 file descriptor를 받아온다.

fd[0]은 해당 공간의 Output을 위한 file descriptor가 되고, fd[1]은 해당 공간의 Input을 위한 file descriptor가 된다.

 

성공 시 0, 실패 시 -1을 반환한다.

 

 

 

> pipe 활용

fork()로 프로세스를 둘로 나누기전에, pipe() 호출로 공유 메모리를 만들어두면 서로 소통할 수 있다.

단, 이때 주의할 것은 아래와 같다.

1. 안쓰는 fd는 닫는다. 예를들어 child에서 데이터를 보내기만 하고 parent에선 데이터를 받기만 할 거라면, child에선 fd[0]을  parent에선 fd[1]을 닫는다.

2. 만약 양방향 소통을 하고 싶다면 그냥 pipe를 두개 만들어서 쓰자. 하나의 pipe로 양방향 통신을 하려면 타이밍이 매우 중요한데, 이를 컨트롤 하는 것은 사실상 불가능하다.

 

pipe()와 fork()를 활용해 IPC를 수행하는 적절한 예제 코드는 아래와 같다.

int main(int argc, char * argv[]) {
    int fds1[2], fds2[2];
    char str1[] = "Who are you?";
    char str2[] = "Thank you for your message";
    char buf[BUF_SIZE];
    
    pipe(fds1), pipe(fds2);  //fork() 전에 pipe() 호출하기!!
    pid_t pid = fork();      //fork()!!
    if (pid == 0) {          //부모 프로세스라면..
        close(fds1[0]), close(fds2[1]);  //쓰지 않는 건 닫기
        write(fds1[1], str1, sizeof(str1));
        read(fds2[0], buf, BUF_SIZE);
        printf("Child process output: %s\n", buf);
    }
    else {                   //자식 프로세스라면..
        close(fds1[1]), close(fds2[0]);  //쓰지 않는 건 닫기
        read(fds1[0], buf, BUF_SIZE);
        printf("Child process output: %s\n", buf);
        write(fds2[1], str2, sizeof(str2));
        sleep(3);
    }
}

//출력 결과
//Parent process output: Who are you?
//Child process output: Thank you for your message

좀비 프로세스 방지하는 부분은 빠졌다. pipe() -> fork() 사용에 집중

fds[]의 값들은 그냥 file descriptor이므로 read()/write() 호출이 가능하다 당연히.

 

 

pipe를 이용해 다른 프로세스에서 client로 부터 받은 데이터를 넘겨주면, file에 저장하도록 코드를 작성할 수 있다.

자세한 코드는 강의자료 nsp-11 p.9 나 과제 코드 참고