유닉스

파이프 - select

hahihi 2022. 11. 20. 01:24

부모 프로세스가 서버 프로세스로 동작, 자신과 통신하는 클라이언트 (자식 프로세스) 를 임의의 수만큼 가지는 경우 사용

#include <sys/time.h>

int select(int nfds, fd_set *readsfs, fd_set *writefs, fd_set *errorfs, struct timeval *timeout);

int main(){
//서버 1, 클라이언트 2인 상황
	int fd1, fd2;
    fd_set readset;
    
    fd1 = open("file1", O_RDONLY);
    fd2 = open(file2", O_RDONLY);
    FD_ZERO(&readset);
    FD_SET(fd1, &readset);
    FD_SET(fd2, &readset);
    switch(select(5,&readset,NULL,NULL,NULL)){ //읽을 데이터 있을 때까지 봉쇄
    
    }
}
  • nfds : 서버가 잠재적 흥미 가지는 (사용할) 파일 기술자의 수
    • 0(stdin), 1(stdout), 2(stderr)는 default, 두 개의 파일을 더 개방하면 nfds = 5
    • fd_set으로 정의된 인수들은 비트마스크
      • 각 비트가 하나의 파일기술자 나타냄, 한 비트 켜져 있으면 해당 파일 기술자에 대한 흥미 나타냄
      • readfs : 읽을 가치 있는 것 있는가?
      • writefs : 임의의 주어진 파일 기술자가 쓰기 받아들일 준비 됐는가?
      • errorfs : 주어진 파일 기술자 중 하나라도 오류 발생했는가?
      • fdset이 가리키는 마스크 관련 함수
        • FD_ZERO(fd set *fdset); - fdset이 가리키는 마스크 초기화
        • FD_SET(int fd, fd_set *fdset); - fdset이 가리키는 마스크 내의 비트, fd를 1로 설정
        • FD_ISSET(int fd, fd_set *fdset); - fdset이 가리키는 마스크내의 비트, fd가 설정되어 있는가?
        • FD_CLR(int fd, fd_set *fdset); - fdset이 가리키는 마스크내의 비트, fd를 0으로 설정
    • timeout : struct timeval 에 대한 포인터
      • 포인터가 NULL : select는 흥미 있는 일 일어날 때까지 봉쇄됨
        timeout이 0초 포함하는 구조 가리키면 즉각 복귀
        0 아닌 값 포함하고 있으면 지정된 시간 후에 복귀
    • select의 복귀 값은 오류 시 -1, 타임 아웃 시 0, 아니면 흥미 있는 파일 기술자의 수 나타내는 정수

 

예시

#define MSGSIZE 6
char *msg1 = "hello";
char *msg2 = "bye!!";

void parent(int p[3][2]);
int child(int[]);

main() {
        int pip[3][2];
        int i;
        for (i=0; i<3; i++) {
                pipe(pip[i]);

                switch(fork()) {
                        case -1: perror("fork call");
                        case 0 : child(pip[i]);
                }
        }
        parent(pip);
        exit(0);
}

void parent(int p[3][2]) {
        char buf[MSGSIZE], ch;
        fd_set set, master;
        int i;

        for (i=0; i<3; i++) close(p[i][1]);
        FD_ZERO(&master);
        FD_SET(0, &master);
        for (i=0; i<3; i++) FD_SET(p[i][0], &master);

        while (set = master, select(p[2][0]+1, &set, NULL, NULL, NULL) > 0) {
                if (FD_ISSET(0, &set)) {
                        printf("From standard input ...");
                        read(0, &ch, 1);
                        printf("%c\n", ch);
                }

                for (i=0; i<3; i++) {
                        if (FD_ISSET(p[i][0], &set)) {
                                if (read(p[i][0], buf, MSGSIZE) > 0) {
                                        printf("Message from child %d\n", i);
                                        printf("MSG=%s\n", buf);
                                }
                        }
                }
                if (waitpid (-1, NULL, WNOHANG) == -1) return;
        }
}

int child(int p[2]) {
        int count;
        close (p[0]);
        for (count = 0; count < 2; count ++) {
                write(p[1], msg1, MSGSIZE);
                sleep(getpid() % 4);
        }
        write(p[1], msg2, MSGSIZE);
        exit(0);
}