본문 바로가기

Programming

SELECT 함수 정리

SELECT 함수는 멀티플렉싱 방식의 IO 모델이다.
즉 한 프로세스에서 여러개의 소켓을 관리하는 방식인데, 관심을 두고 싶은 소켓을 각각의 셋트( 읽기, 쓰기, 예외 )에 넣어서
변화를 감시하고, 변화가 일어났을때 IO 를 하는 방식이라는 것이다.

한마디로 풀어보자면, IO를 하라는 통지가 먼저 일어나고, 그 통지에 의한 각각의 IO 처리를 진행하는 방식이다.

리눅스 기반과 윈도우즈 기반의 SELECT 함수는 같지만 작동 원리가 약간 틀리다.

리눅스 기반부터 살펴보자.

리눅스의 fd_set 구조체
typedef struct
{
 __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
} fd_set;

__FD_SETSIZE 가 결정 하는듯한데.
ulimit -a 에서 open files 가 1024 이니.... fd_mask가 1024/64(8 * sizeof (__fd_mask== long)) --> 16개이고
fd_mask가 8 byte 니깐 16 * 8 -> 128byte
fd_set 내부적으로 bit 처리 하는것으로 알고 있으니..* 8 해주면 1024 개의 디스크립터를 받을수 있다.

윈도우즈
typedef struct fd_set {
        u_int fd_count;               // 변화가 발생한 소켓 개수
        SOCKET  fd_array[FD_SETSIZE];  // 총 64개 소켓
} fd_set;
FD_SETSIZE =>64

윈도우즈는 한 fd_set당 64개의 소켓을 넣을수 있고, 리눅스는 fd_set당 1024개의 파일 디스크립트를 등록할수 있다.
하지만, 리눅스에서는 한 프로세스에서의 최대 파일 디스크립터가 1024로 제한된다.
( 커널을 조작하는 방법이 있다는데 크게 중요하진 않은거 같다. epoll 을 쓰는것이 더 효율적이다. )

timeval wait_time;
wait_time.tv_sec = 0;
wait_time.tv_usec = 1000;

fd_set read_fds;
FD_ZERO( &read_fds );
FD_SET( sock, &read_fds );

int result = select( sock + 1, &read_fds, 0, 0, &wait_time );

코드는 같지만, 리눅스와 윈도우의 작동 원리가 약간 틀리다.

select 함수 순서
1. 읽기셋을 하나 만들고, 초기화 한다.
2. 변화를 체크하려는 sock 을 읽기셋에 등록한다.
3. select 함수( 검사하고자 하는 소켓 + 1, 읽기셋 주소, 쓰기셋 주소, 예외셋 주소, 타임아웃 시간 설정 )

readfds => 읽어들일 데이타가 있는지가 검사되며, 정확히는 읽기가 봉쇄되지 않았는지를 검사한다. 봉쇄되지 않음을 검사함으로 (EOF)end-of-file가 발생하는 것도 검사하고 리턴시킬수 있다. 즉, TCP recv 버퍼에서 가져올수 있는 데이터가 있는지 검사한다.

writefds => send 버퍼로 데이터를 전송할수 있는 상태인지 검사한다. ( 즉 출력 버퍼에 충분한 여유공간이 있는가 )
exceptfds => 예외상황이 발생했는지 검사한다.

리눅스일경우 한 프로세스당 1024개의 파일 디스크립터를 받을수 있으므로,
sock의 값은 1~1023까지가 유효하다. ( 0은 표준 입력 디스크립터 )
그래서 select 함수의 첫번째 인자는 검사하고자 하는 파일 디스크립터의 최대값 이다.
만약 sock의 값이 1023 이라면, select 함수 검사시 , 읽기셋을 0번 비트부터 1023번 비트까지 총 1024개의 디스크립터를
체크해야 하는 비용이 든다.

wait_time은 time_out 시간을 지정할수 있다.
wait_time 변수의 메모리값 대신, 0을 인자로 넣으면 파일 디스크립터에 변화가 발생할때까지 무한 대기한다.

윈도우의 경우는 구조체 부터 틀리다.
FD_SET( 1023, &read_fds ) 을 하게 되면,
fd_array[ 0 ] 에 1023의 소켓 번호가 저장된다.
또한 변화가 발생했을경우 구조체의 fd_count 값에 변화가 발생한 소켓 개수가 저장된다.
윈도우의 경우 select 함수의 첫번째인자는 무시된다.

리턴값
-1 : 오류발생
0 : 타임아웃에 의한 리턴
0 이상 : 변화 발생한 디스크립터 개수

변화 발생한 소켓 ( 디스크립터 ) 체크
FD_ISSET( sock, &readfds ) => 읽기셋에서 변화가 발생했는지 체크

'Programming' 카테고리의 다른 글

CPPUNIT 테스트  (0) 2011.01.07
기초지식 정리  (0) 2010.12.20
IOCP 정리  (0) 2010.12.02
리눅스 SIGPIPE 처리  (0) 2010.11.29
compile - error 팁  (0) 2009.08.10