select()는 리눅스 / 유닉스 시스템에서 여러 파일 디스크립터를 동시에 감시하여, 읽기/쓰기/예외 이벤트가 발생한 파일 디스크립터를 감지할 수 있게 해주는 함수다.

 

  • 여러 클라이언트의 요청을 동시에 처리할 수 있게 해준다.
  • 여러 소켓을 동시에 감시할 수 있게 해준다.
  • 단일 스레드 기반의 네트워크 서버에서 효율적으로 동시성 처리가 가능하다.
  • 하지만 최대로 감지할 수 있는 클라의 수가 윈도우는 64개, 리눅스는 1024개 이기 때문에 제한이 있다.

 

✅ 예제

 

UINT nCount
FD_SET fdRead;
std::list<SOCKET>::iterator it;

// 클라 접속 및 정보 수신 변화 감시셋을 초기화 한다.
FD_ZERO(&fdRead);
for(it = g_listClient.begin(); it != g_listClient.end(); ++it)
{
    FD_SET(*it, &fdRead);
}

// 변화가 발생할 때까지 대기한다.
::select(0, &fdRead, NULL, NULL, NULL);

// 변화가 감지된 소켓을 확인한다.
nCount = fdRead.fd_count;
for(int nIndex = 0; nIndex < nCount; ++nIndex)
{
    // 소켓에 변화 감시 플래그가 설정 되었는지 확인한다.
    if(!FD_ISSET(fdRead.fd_array[nIndex], &fdRead))
    {
        continue;
    }
    
    // 감지된 소켓이 listen 소켓인지 확인한다.
    // 다시 말해, 클라가 연결을 시도했는지 여부를 확인한다.
    if(fdRead.fd_array[nIndex] == g_hSocket)
    {
        // 새 클라이언트의 접속을 받는다.
        SOCKADDR_IN clientaddr = { 0 };
        int nAddrLen = sizeof(clientaddr);
        SOCKET hClient = ::accept(g_hSocket, (SOCKADDR*)&clientaddr, &nAddrLen);
        if(hClient != INVALID_SOCKET)
        {
            FD_SET(hClient, &fdRead);
            g_listClient.push_back(hClient);
        }
    }
    else // 클라이언트가 전송한 데이터가 있을 경우
    {
        char szBuffer[1024] = { 0 };
        int nReceive = ::recv(fdRead.fd_array[nIndex], (char*)szBuffer, sizeof(szBuffer), 0);
    }
}

+ Recent posts