더북(TheBook)

3.6.3 select() 함수

논블로킹 소켓을 프레임마다 폴링하는 방식은, 간편하면서도 스레드를 블로킹하지 않고 데이터가 수신된 것이 있는지 확인할 수 있어 직관적인 방법이다. 하지만 폴링해야 할 소켓의 수가 상당히 많다면 이 방법도 효율이 떨어지게 된다. 이에 대한 대안으로 소켓 라이브러리에는 여러 소켓을 한꺼번에 확인하고 그중 하나라도 준비되면 즉시 대응할 수 있는 방법이 마련되어 있다. 바로 select() 함수가 그것이다.

int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
    const timeval* timeout);

POSIX 플랫폼에선 nfds에 소켓 식별자를 넣는데, 확인하려는 소켓의 식별자 중 최고 높은 숫자여야 한다. POSIX에서 소켓 식별자는 그냥 정수에 불과하므로 함수에 넘기는 소켓의 값 중 최댓값을 넘기면 된다. 윈도에선 소켓이 정수형이 아니라 포인터형이므로 이 인자는 무시되며 아무 역할도 하지 않는다.

readfds는 소켓 컬렉션을 가리키는 포인터이며 fd_set형이다. 읽을 준비가 되었는지 확인하고 싶은 소켓을 여기에 넣어준다. 여러 소켓을 지정해 fd_set 집합을 만드는 법은 뒤에 설명할 텐데, readfds 집합에 포함된 소켓으로 패킷이 도착하면 select() 함수는 최대한 빨리 블로킹 상태에서 빠져나와 호출 스레드로 리턴한다. 리턴 시점이 되어서도 패킷을 수신하지 못한 소켓은 전부 집합에서 걸러진다. 따라서 select()가 리턴하였을 때 아직 readfds 집합에 남아있는 소켓은 읽을 데이터가 있는 상태이며, 여기서 데이터를 읽으면 블로킹되지 않고 읽을 수 있다. readfdsnullptr를 넘기면 읽기 가능한 소켓이 있는지 체크하지 않고 넘어간다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.