WSAWaitForMultipleEvents 함수(winsock2.h)

WSAWaitForMultipleEvents 함수는 지정된 이벤트 개체 중 하나 또는 전부가 신호 상태에 있거나 시간 제한 간격이 만료되거나 I/O 완료 루틴이 실행된 경우 를 반환합니다.

구문

DWORD WSAAPI WSAWaitForMultipleEvents(
  [in] DWORD          cEvents,
  [in] const WSAEVENT *lphEvents,
  [in] BOOL           fWaitAll,
  [in] DWORD          dwTimeout,
  [in] BOOL           fAlertable
);

매개 변수

[in] cEvents

lphEvents가 가리키는 배열의 이벤트 개체 핸들 수입니다. 이벤트 개체 핸들의 최대 수는 WSA_MAXIMUM_WAIT_EVENTS. 하나 이상의 이벤트를 지정해야 합니다.

[in] lphEvents

이벤트 개체 핸들의 배열에 대한 포인터입니다. 배열에는 다양한 형식의 개체 핸들이 포함될 수 있습니다. fWaitAll 매개 변수가 TRUE로 설정된 경우 동일한 핸들의 여러 복사본을 포함하지 않을 수 있습니다. 대기가 보류 중인 동안 이러한 핸들 중 하나가 닫히면 WSAWaitForMultipleEvents 의 동작이 정의되지 않습니다.

핸들에는 SYNCHRONIZE 액세스 권한이 있어야 합니다. 자세한 내용은 표준 액세스 권한을 참조하세요.

[in] fWaitAll

대기 유형을 지정하는 값입니다. TRUE이면 lphEvents 배열에 있는 모든 개체의 상태가 신호를 받으면 함수가 반환됩니다. FALSE이면 이벤트 개체가 신호를 받으면 함수가 반환됩니다. 후자의 경우 반환 값에서 WSA_WAIT_EVENT_0 빼기 상태는 함수가 반환되도록 한 이벤트 개체의 인덱스입니다. 호출 중에 둘 이상의 이벤트 개체가 신호를 받은 경우 신호가 있는 모든 이벤트 개체의 인덱스 값이 가장 작은 신호 이벤트 개체에 대한 배열 인덱스입니다.

[in] dwTimeout

제한 시간 간격(밀리초)입니다. wSAWaitForMultipleEventsfWaitAll 매개 변수에 지정된 조건이 충족되지 않더라도 제한 시간 간격이 만료되면 를 반환합니다. dwTimeout 매개 변수가 0이면 WSAWaitForMultipleEvents는 지정된 이벤트 개체의 상태를 테스트하고 즉시 반환합니다. dwTimeoutWSA_INFINITE 경우 WSAWaitForMultipleEvents는 영원히 기다립니다. 즉, 제한 시간 간격은 만료되지 않습니다.

[in] fAlertable

시스템에서 I/O 완료 루틴을 실행할 수 있도록 스레드가 경고 가능한 대기 상태에 배치되는지 여부를 지정하는 값입니다. TRUE이면 스레드가 경고 대기 상태에 배치되고 시스템이 I/O 완료 루틴을 실행할 때 WSAWaitForMultipleEvents가 반환될 수 있습니다. 이 경우 WSA_WAIT_IO_COMPLETION 반환되고 대기 중인 이벤트는 아직 신호를 받지 않습니다. 애플리케이션은 WSAWaitForMultipleEvents 함수를 다시 호출해야 합니다. FALSE이면 스레드가 경고 가능한 대기 상태에 배치되지 않고 I/O 완료 루틴이 실행되지 않습니다.

반환 값

WSAWaitForMultipleEvents 함수가 성공하면 성공 시 반환 값은 다음 값 중 하나입니다.

반환 값 의미
WSA_WAIT_EVENT_0 (WSA_WAIT_EVENT_0 + cEvents - 1)
fWaitAll 매개 변수가 TRUE이면 반환 값은 지정된 모든 이벤트 개체에 신호가 표시됨을 나타냅니다.

fWaitAll 매개 변수가 FALSE이면 반환 값에서 WSA_WAIT_EVENT_0 빼기는 대기를 충족하는 신호 이벤트 개체의 lphEvents 배열 인덱스를 나타냅니다. 호출 중에 둘 이상의 이벤트 개체가 신호를 받으면 반환 값은 신호를 받은 모든 이벤트 개체의 인덱스 값이 가장 작은 신호 이벤트 개체의 lphEvents 배열 인덱스를 나타냅니다.

WSA_WAIT_IO_COMPLETION
실행된 하나 이상의 I/O 완료 루틴으로 대기가 종료되었습니다. 대기 중인 이벤트는 아직 신호가 표시되지 않습니다. 애플리케이션은 WSAWaitForMultipleEvents 함수를 다시 호출해야 합니다. 이 반환 값은 fAlertable 매개 변수가 TRUE인 경우에만 반환할 수 있습니다.
WSA_WAIT_TIMEOUT
시간 제한 간격이 경과하고 fWaitAll 매개 변수에 지정된 조건이 충족되지 않았습니다. I/O 완료 루틴이 실행되지 않았습니다.
 

WSAWaitForMultipleEvents 함수가 실패하면 반환 값이 WSA_WAIT_FAILED. 다음 표에서는 WSAGetLastError 와 함께 확장된 오류 정보를 가져오는 데 사용할 수 있는 값을 나열합니다.

오류 코드 의미
WSANOTINITIALISED 이 함수를 사용하기 전에 성공적인 WSAStartup 호출이 발생해야 합니다.
WSAENETDOWN 네트워크 하위 시스템이 실패했습니다.
WSAEINPROGRESS 차단 Windows Sockets 1.1 호출이 진행 중이거나 서비스 공급자가 여전히 콜백 함수를 처리하고 있습니다.
WSA_NOT_ENOUGH_MEMORY 사용 가능한 메모리가 부족하여 작업을 완료할 수 없습니다.
WSA_INVALID_HANDLE lphEvents 배열의 값 중 하나 이상이 유효한 이벤트 개체 핸들이 아닙니다.
WSA_INVALID_PARAMETER cEvents 매개 변수에 유효한 핸들 수가 없습니다.

설명

WSAWaitForMultipleEvents 함수는 대기 조건이 충족되었는지 여부를 결정합니다. 조건이 충족되지 않으면 호출 스레드가 대기 상태가 됩니다. 조건이 충족될 때까지 기다리는 동안 프로세서 시간을 사용하지 않습니다.

WSAWaitForMultipleEvents 함수는 지정된 개체 중 하나 또는 전부가 신호 상태이거나 제한 시간 간격이 경과할 때 를 반환합니다.

bWaitAll 매개 변수가 TRUE이면 모든 개체의 상태가 신호로 설정된 경우에만 대기 작업이 완료됩니다. 함수는 모든 개체의 상태가 신호로 설정될 때까지 지정된 개체의 상태를 수정하지 않습니다.

bWaitAll 매개 변수가 FALSE이면 WSAWaitForMultipleEvents는 개체 중 하나가 신호를 수신할 때까지 인덱스 0부터 시작하여 lphEvents 배열의 핸들을 확인합니다. 여러 개체가 신호를 받으면 함수는 개체가 신호를 받은 lphEvents 배열에서 첫 번째 핸들의 인덱스를 반환합니다.

이 함수는 fAlertable 매개 변수를 TRUE로 설정하여 경고 대기를 수행하는 데도 사용됩니다. 이렇게 하면 시스템이 호출 스레드에 의해 I/O 완료 루틴을 실행할 때 함수가 를 반환할 수 있습니다.

시스템이 I/O 완료 루틴(비동기 프로시저 호출 또는 APC)을 실행하려면 스레드가 경고 가능한 대기 상태여야 합니다. 따라서 I/O 완료 루틴이 있고 fAlertable 매개 변수가 FALSE인 보류 중인 비동기 작업이 있을 때 애플리케이션이 WSAWaitForMultipleEvents를 호출하는 경우 해당 I/O 작업이 완료된 경우에도 해당 I/O 완료 루틴이 실행되지 않습니다.

fAlertable 매개 변수가 TRUE이고 보류 중인 작업 중 하나가 완료되면 APC가 실행되고 WSAWaitForMultipleEventsWSA_IO_COMPLETION 반환합니다. 보류 중인 이벤트는 아직 신호를 받지 않았습니다. 애플리케이션은 WSAWaitForMultipleEvents 함수를 다시 호출해야 합니다.

이벤트 개체가 신호를 받을 때까지 기다리지 않고 경고 가능한 대기 상태가 필요한 애플리케이션은 Windows SleepEx 함수를 사용해야 합니다.

WSAWaitForMultipleEvents의 현재 구현은 WaitForMultipleObjectsEx 함수를 호출합니다.

참고 직접 또는 간접적으로 창을 만드는 코드로 WSAWaitForMultipleEvents 를 호출할 때는 주의해야 합니다. 스레드가 창을 만드는 경우 메시지를 처리해야 합니다. 메시지 브로드캐스트는 시스템의 모든 창으로 전송됩니다. 시간 제한 없이 WSAWaitForMultipleEvents 를 사용하는 스레드( dwTimeout 매개 변수 가 WSA_INFINITE 설정됨)로 인해 시스템이 교착 상태가 될 수 있습니다.
 

예제 코드

다음 코드 예제에서는 WSAWaitForMultipleEvents 함수를 사용하는 방법을 보여 줍니다.
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

#define DATA_BUFSIZE 4096

int main()
{
    //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData = { 0 };
    int iResult = 0;
    BOOL bResult = TRUE;

    WSABUF DataBuf;
    char buffer[DATA_BUFSIZE];

    DWORD EventTotal = 0;
    DWORD RecvBytes = 0;
    DWORD Flags = 0;
    DWORD BytesTransferred = 0;

    WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
    WSAOVERLAPPED AcceptOverlapped;
    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET AcceptSocket = INVALID_SOCKET;

    DWORD Index;

    //-----------------------------------------
    // Initialize Winsock
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed: %d\n", iResult);
        return 1;
    }
    //-----------------------------------------
    // Create a listening socket bound to a local
    // IP address and the port specified
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error = %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    u_short port = 27015;
    char *ip;
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_port = htons(port);
    hostent *thisHost;

    thisHost = gethostbyname("");
    if (thisHost == NULL) {
        wprintf(L"gethostbyname failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    ip = inet_ntoa(*(struct in_addr *) *thisHost->h_addr_list);

    service.sin_addr.s_addr = inet_addr(ip);

    //-----------------------------------------
    // Bind the listening socket to the local IP address
    // and port number
    iResult = bind(ListenSocket, (SOCKADDR *) & service, sizeof (SOCKADDR));
    if (iResult != 0) {
        wprintf(L"bind failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //-----------------------------------------
    // Set the socket to listen for incoming
    // connection requests
    iResult = listen(ListenSocket, 1);
    if (iResult != 0) {
        wprintf(L"listen failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    wprintf(L"Listening...\n");

    //-----------------------------------------
    // Accept and incoming connection request
    AcceptSocket = accept(ListenSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET) {
        wprintf(L"accept failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    wprintf(L"Client Accepted...\n");

    //-----------------------------------------
    // Create an event handle and setup an overlapped structure.
    EventArray[EventTotal] = WSACreateEvent();
    if (EventArray[EventTotal] == WSA_INVALID_EVENT) {
        wprintf(L"WSACreateEvent failed with error = %d\n", WSAGetLastError());
        closesocket(AcceptSocket);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    ZeroMemory(&AcceptOverlapped, sizeof (WSAOVERLAPPED));
    AcceptOverlapped.hEvent = EventArray[EventTotal];

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;

    EventTotal++;

    //-----------------------------------------
    // Call WSARecv to receive data into DataBuf on 
    // the accepted socket in overlapped I/O mode
    if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) ==
        SOCKET_ERROR) {
        iResult = WSAGetLastError();
        if (iResult != WSA_IO_PENDING)
            wprintf(L"WSARecv failed with error = %d\n", iResult);
    }
    //-----------------------------------------
    // Process overlapped receives on the socket
    while (1) {

        //-----------------------------------------
        // Wait for the overlapped I/O call to complete
        Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);

        //-----------------------------------------
        // Reset the signaled event
        bResult = WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
        if (bResult == FALSE) {
            wprintf(L"WSAResetEvent failed with error = %d\n", WSAGetLastError());
        }
        //-----------------------------------------
        // Determine the status of the overlapped event
        bResult =
            WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE,
                                   &Flags);
        if (bResult == FALSE) {
            wprintf(L"WSAGetOverlappedResult failed with error = %d\n", WSAGetLastError());
        }
        //-----------------------------------------
        // If the connection has been closed, close the accepted socket
        if (BytesTransferred == 0) {
            wprintf(L"Closing accept Socket %d\n", AcceptSocket);
            closesocket(ListenSocket);
            closesocket(AcceptSocket);
            WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
            WSACleanup();
            return 1;
        }
        //-----------------------------------------
        // If data has been received, echo the received data
        // from DataBuf back to the client
        iResult =
            WSASend(AcceptSocket, &DataBuf, 1, &RecvBytes, Flags, &AcceptOverlapped, NULL);
        if (iResult != 0) {
            wprintf(L"WSASend failed with error = %d\n", WSAGetLastError());
        }
        //-----------------------------------------         
        // Reset the changed flags and overlapped structure
        Flags = 0;
        ZeroMemory(&AcceptOverlapped, sizeof (WSAOVERLAPPED));

        AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];

        //-----------------------------------------
        // Reset the data buffer
        DataBuf.len = DATA_BUFSIZE;
        DataBuf.buf = buffer;
    }

    closesocket(ListenSocket);
    closesocket(AcceptSocket);
    WSACleanup();

    return 0;
}


Windows Phone 8: 이 함수는 Windows Phone 8 이상에서 Windows Phone 스토어 앱에서 지원됩니다.

Windows 8.1Windows Server 2012 R2: 이 함수는 Windows 8.1, Windows Server 2012 R2 이상의 Windows 스토어 앱에서 지원됩니다.

요구 사항

   
지원되는 최소 클라이언트 Windows 8.1, Windows Vista [데스크톱 앱 | UWP 앱]
지원되는 최소 서버 Windows Server 2003 [데스크톱 앱 | UWP 앱]
대상 플랫폼 Windows
헤더 winsock2.h
라이브러리 Ws2_32.lib
DLL Ws2_32.dll

추가 정보

표준 액세스 권한

WSACloseEvent

WSACreateEvent

WaitForMultipleObjectsEx

Winsock 함수

Winsock 참조