학습 목표


Select

select()는 싱글 쓰레드로 다중 I/O를 처리하는 멀티플렉싱 통지모델의 가장 대표적인 방법이다. 해당 파일 디스크립터가 I/O를 할 준비가 되었는지 알 수 있다면, 그 파일 디스크립터가 할당받은 커널버퍼에 데이터를 복사해주기만 하면 된다.

select는 많은 파일 디스크립터(최대 1024개)들을 한꺼번에 관찰하는 FD_SET 구조체를 사용하여 빠르고 간편하게 유저에게 파일 디스크립터의 상황을 알려준다.

#include <sys/select.h>
//select는 read, write, error 3가지 i/o에 대한 통지를 받는다.
//추가로 대기시간 설정 가능.
int select(int nfds, fd_set *restrict readfds,
           fd_set *restrict writefds, fd_set *restrict exceptfds,
           struct timeval *restrict timeout);
/**
 *   @param nfds: 파일 디스크럽터의 관찰 범위 (0 ~ nfds-1)
 *   @param readfds: read I/O를 통지받을 FD_SET의 주소, 없으면 NULL
 *   @param writefds: write I/O를 통지받을 FD_SET의 주소, 없으면 NULL
 *   @param exceptfds: error(?) I/O를 통지받을 FD_SET의 주소, 없으면 NULL 
 *   @param timeout: NULL이면 변화가 있을 때까지 block, 변수 값 만큼 대기후 timeout.
 *
 *   @return: 데이터가 변경된 파일의 개수. 즉 fd_set에서 비트 값이 1인 필드의 개수를 반환.
 */

// select 함수는 fd_set에 등록된 파일들에 데이터 변경이 있는지를 timeout동안 기다린다.
// 만약 timeout 시간동안 변경이 없다면 0을 반환.
// timeout 이 null일 경우, 데이터가 있을 때까지 무한정 기다리고, 멤버 값이 모두 0이면 즉시 반환.

// 리턴값이 데이터가 변경된 fd의 목록이 아니기 때문에, 리턴값이 1이고 최대 파일 지정번호가 1000이라면
// 0부터 루프를 순환해서 몇번째 fd가 변경이 되었는지 검사해야한다.

FD_SET


typedef struct
{
	int fds_bits[32];
} fd_set;
//32개의 int를 가지는 배열이고, int는 32bit(4byte)로 구성되어 있으니
//총 32 * 32bit 만큼의 fd를 저장할 수 있다. (1024개)

void FD_CLR(int fd, fd_set *set); //fd_set으로 추가한 fd값을 제거
int  FD_ISSET(int fd, fd_set *set); //rfds 변수에 특정FD값이 설정되어있는지 판단.
void FD_SET(int fd, fd_set *set); //fd_socket(fd)에 저장된 정수값을 고유값으로 판단하여 rfds(set)변수에 해당 값에 할당된 비트를 1로 만들어준다.
void FD_ZERO(fd_set *set); //32회 반복해서 fds_bits배열의 각 항목에 0을 넣겠다.

fd_set 구조체는 1024크기를 가지는 비트 배열을 포함하고, 파일 지정 번호는 각 비트 배열 첨자에 대응되는 구조를 가진다. 예를 들어 fd가 3이면 4번째 비트배열에 대응된다. (배열은 0부터 시작하기 때문)

만약 변경된 데이터가 있다면 해당 비트값이 1로 설정이 된다.

프로그램은 이 비트 값을 검사함으로써 어떤 파일 지정번호(fd)에서 변경이 일어났는지 알게 되고,