IPC - 리눅스 Named PIPE 사용법 (FIFO)

Language/C 2011. 9. 16. 09:21

리눅스에서는 Named PIPE 기법을 위해 FIFO 라는 특수 파일을 제공합니다.

특수 파일로 생성되는 FIFO 는 생성 방법에 차이는 있지만 PIPE 와 거의 유사합니다.


익명의 파이프는 따로 이름이 없는 통신 채널인데 비해서 

FIFO 는 mkfifo 함수에 의해 실제로 생성되는 특수 파일입니다.


따라서 어떤 프로세스라도 생성된 경로로 파일에 접근하여

다른 파일을 사용하듯 읽거나 쓸 수 있습니다.


FIFO 를 사용하기 위해서는 mkfifo() 함수를 사용하는데

함수의 설명은 표로 정리해 보겠습니다.


함수 원형

int mkfifo(const char *pathname, mode_t mode)

인자

const char *pathname

fifo 파일이 생성될 경로를 지정한다.

일반 파일의 경로를 지정하는 것과 동일

mode_t mode

생성 될 fifo 파일의 접근 권한을 지정한다.

반환 값

성공하는 경우 0 반환

실패하는 경우 -1 반환


mkfifo() 함수가 정상적으로 실행되면 

인자로 넘긴 경로에 특수 파일로 FIFO 가 등록됩니다.


다른 프로세스는 일반 파일에서 사용하는 것처럼 FIFO를 사용 가능하지만 

특정 프로세스가 FIFO 를 쓰기용으로 열기 전까지는 다른 읽기용 개방은 블럭(Block) 됩니다.


예제를 통해 실제 사용법을 알아보겠습니다.


만들어보고자 하는 예제는 두개의 프로세스가 FIFO 를 이용해 통신하며

Sender 프로세스가 보낸 메시지를 Receiver 프로세스가 메시지를 읽어서 화면에 보여주는 프로그램입니다.


Sender 프로세스가 메시지를 3번 보내고 

Receiver 프로세스도 세번 메시지를 읽도록 하겠습니다.


먼저 Receiver 프로세스 코드입니다.

Receiver 프로세스는 Named PIPE 인 FIFO 를 생성하고 메시지를 기다립니다.



 #include <fcntl.h>

#include <sys/stat.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>


#define MSG_SIZE 80


int main()

{

    char msg[MSG_SIZE];

    int filedes;

    int nread, cnt;


    if(mkfifo("./fifo",0666) == -1){

        printf("fail to call fifo()\n");

        exit(1);

    }


    if((filedes = open("./fifo", O_RDWR)) < 0){

        printf("fail to call fifo()\n");

        exit(1);

    }


    for(cnt=0; cnt<3; cnt++){

        if((nread = read(filedes, msg, MSG_SIZE)) < 0 ){

            printf("fail to call read()\n");

            exit(1);

        }

        printf("recv: %s\n", msg);

    }

    unlink("./fifo");


    return 0;

}



소스를 부분 별로 살펴보겠습니다.




파일 디스크립터(File Descriptor) 를 얻을 변수와 

메시지를 저장할 변수를 선언하였습니다.





Named PIPE 특수 파일인 FIFO 를 생성하는 부분입니다.

mkfifo() 함수에 현재 경로는 프로그램이 실행되는 폴더인 "./fifo" 로 지정하였고,

파일의 권한은 0666 으로 owner, group, user 모두 읽기 쓰기 권한을 주었습니다.




fifo 를 개방하는 부분입니다. 

이때 주의할 부분은 최초 개방할 때는 반드시 쓰기 권한이 있어야 합니다.

위에서도 한번 설명 했듯이 fifo 는 최초 쓰기 개방전에는 모든 읽기 개방을 Block 해 버립니다.


여기서는 Receiver 프로세스가 최초 개방이므로 

O_RDWR 읽기 쓰기 모두 가능 모드로 개방하였습니다.




fifo 파일에서 정해진 사이즈만큼 읽어 들입니다. 

pipe 의 특성 상 정해진 바이트를 읽을 때까지 대기를 하게 됩니다.

정해진 사이즈의 데이터를 읽으면 화면에 메시지를 출력합니다.



unlink() 함수로 fifo 와 연결을 끊고 프로그램을 종료하는 부분입니다.


이제 Sender 의 소스를 보겠습니다.


 #include <fcntl.h>

#include <sys/stat.h>

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>


#define MSG_SIZE 80


int main()

{

    char msg[MSG_SIZE];

    int filedes;

    int cnt;


    // open fifo file

    if((filedes = open("./fifo", O_WRONLY)) < 0){

        printf("fail to call open()\n");

        exit(1);

    }


    for(cnt=0; cnt<3; cnt++){

        printf("input a message : ");

        gets(msg);

        msg[MSG_SIZE-1] = '\0';


        if(write(filedes, msg, MSG_SIZE)==-1){

            printf("fail to call write()\n");

            exit(1);

        }

        sleep(1);

    }

}




Sender 쪽 소스도 부분별로 살펴보겠습니다.




fifo 파일을 엽니다. fifo 파일의 패스(path) 를 안다면 

어떤 프로세스도 일반 파일을 여는 것처럼 fifo 파일을 열 수 있습니다.




일반 파일에 쓰는 것과 똑같이 fifo 에 문자열을 쓰고 있습니다.

다만 fifo 는 파이프(pipe) 로 작동 하므로 상대 프로세스로 메시지가 전달되게 됩니다.


실행해서 결과를 확인해 보겠습니다.

실행할 때의 주의점은 Receiver 프로세스와 

Sender 프로세스가 같은 폴더에 있어야 한다는 것입니다.


fifo 파일의 경로를 상대 경로 "./" 으로 하였기 때문에

같은 폴더에 있어야 파일에 접근할 수 있는 것이죠.


물론 절대경로로 fifo 를 설정하면 실행파일이 같이 있을 필요는 없지만

소스를 그렇게 코딩 했으므로 같은 폴더에 넣고 실행하도록 하겠습니다.





터미널을 두개 열고 각 프로세스를 실행시킨 결과 화면입니다.





그림에서 보는 것처럼 Sender 프로세스가 메시지를 쓰고 엔터키를 누를 때마다

Receiver 프로세스는 전달 받은 메시지를 그대로 화면에 출력합니다.

같은 동작이 세번 반복 되면 프로그램이 끝나게 됩니다.


Named PIPE 역시 사용하기에 따라 여러가지 응용이 가능하다고 생각합니다.

출처 :  
http://akj61300.blog.me/80133137262 

'Language > C' 카테고리의 다른 글

시리얼 통신 - 자료 수신을 위한 poll  (0) 2011.09.16
IPC - 파이프(PIPE)의 개념  (0) 2011.09.16
named pipe / FIFO  (0) 2011.09.15
01. 링킹의 기본 이해  (0) 2011.09.08
03. gcc를 사용해 원하는 컴파일 하기  (0) 2011.09.08
: