본문 바로가기
IT/programming

[C/C++] select 를 활용한 non-block I/O, FD_SET, FD_ISSET

by 어느해겨울 2022. 1. 14.

select를 활용한 event check, FD_SET, FD_ISSET

select() 를 이용하여 non-block I/O 처리를 만들어보겠다.

크게 아래의 과정을 거쳐서 동작한다.

 1. FD_SET 을 통한 descriptor 셋팅

 2. FD_SET된 FD_LIST들을 select() 를 통해 event 검사

 3. timeout 시 동작할 행위

 4. timeout 전 event 발생 시 FD_ISSET 처리

 

소스코드 내에 주석을 달아뒀으니 참고하여 활용하자.

 

소스코드

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <fcntl.h>


int main(int _argc, char *_argv[]) {
    int     rc;
    struct  timeval t_timeout;

    // device의 open이 되었다고 가정하고 진행한다.
    int     dev_fd = 3;
    int     max_fd = dev_fd + 1;

    fd_set  fd_reads;

    while( 1 ) {
        FD_ZERO(&fd_reads);
        FD_SET(dev_fd, &fd_reads);

        // timeout: 최대 1초까지 event 대기
        t_timeout.tv_sec  = 1;  // sec
        t_timeout.tv_usec = 0;  // msec

        // fd_reads에 FD_SET 된 descriptor들을 최대 t_timeout에 설정된 시간만큼 기다린다.
        if( (rc = select(max_fd, &fd_reads, NULL, NULL, &t_timeout)) < 0 ) {
            printf("execute() select failed : [%02d] %s\n", errno, strerror(errno));

            continue;


        // t_timeout에 설정된 시간까지 event가 없다면 timeout 처리된다.
        } else if( rc == 0 ) {
            printf("select() timeout, continue loop..\n");
            continue;
        }

        // timeout 전에 event가 발생했다.
        // FD_ISSET 을 이용하여 fd_reads 중 어느 descriptor에서 event가 발생했는지 확인한다.
        if( FD_ISSET(dev_fd, &fd_reads) ) {
            printf("select() event [dev_fd]\n");
        }
    }

    return 0;
}

이번 예제에서는 1개의 descriptor 만 사용했지만 복수개(e.g. socket client..)의 descriptor의 event를 감시해야 할 때는 배열을 생성하여 배열에 descriptor들을 넣어주고 FD_SET을 통해 fd_reads에 set을 하자.

그리고 event 발생 시 FD_ISSET을 배열에 저장된 descriptor의 갯수만큼 반복하여 체크하면 된다.

 

끝.

 

 

댓글