WSAWaitForMultipleEvents 関数 (winsock2.h)

WSAWaitForMultipleEvents 関数は、指定したイベント オブジェクトの 1 つ以上がシグナル状態の場合、タイムアウト間隔が切れた場合、または 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。 1 つ以上のイベントを指定する必要があります。

[in] lphEvents

イベント オブジェクト ハンドルの配列へのポインター。 配列には、さまざまな型のオブジェクトのハンドルを含めることができます。 fWaitAll パラメーターが TRUE に設定されている場合、同じハンドルの複数のコピーが含まれていない可能性があります。 待機がまだ保留中の間にこれらのハンドルのいずれかが閉じられた場合、 WSAWaitForMultipleEvents の動作は未定義です。

ハンドルには SYNCHRONIZE アクセス権が必要です。 詳細については、「 Standard Access Rights」を参照してください。

[in] fWaitAll

待機の種類を指定する値。 TRUE の場合、lphEvents 配列内のすべてのオブジェクトの状態が通知されると、関数が返されます。 FALSE の場合、イベント オブジェクトのいずれかが通知されたときに関数が返されます。 後者の場合、戻り値 からWSA_WAIT_EVENT_0 を引いた値は、関数が返された状態のイベント オブジェクトのインデックスを示します。 呼び出し中に複数のイベント オブジェクトがシグナル化された場合、これはシグナルイベントオブジェクトへの配列インデックスであり、すべてのシグナルイベントオブジェクトのインデックス値が最も小さくなります。

[in] dwTimeout

タイムアウト間隔 (ミリ秒単位)。 WSAWaitForMultipleEvents は、 fWaitAll パラメーターで指定された条件が満たされていない場合でも、タイムアウト間隔が切れた場合に返されます。 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 + cEvents - 1) へのWSA_WAIT_EVENT_0
fWaitAll パラメーターが TRUE の場合、戻り値は、指定されたすべてのイベント オブジェクトにシグナルが送信されることを示します。

fWaitAll パラメーターが FALSE の場合、戻り値から WSA_WAIT_EVENT_0 を引いた値は、待機を満たすシグナルイベント オブジェクトの lphEvents 配列インデックスを示します。 呼び出し中に複数のイベント オブジェクトがシグナル化された場合、戻り値は、シグナルイベント オブジェクトの lphEvents 配列インデックスと、すべてのシグナルイベントオブジェクトの最小インデックス値を示します。

WSA_WAIT_IO_COMPLETION
待機は、実行された 1 つ以上の 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 配列内の 1 つ以上の値が有効なイベント オブジェクト ハンドルではありません。
WSA_INVALID_PARAMETER cEvents パラメーターに有効なハンドル数が含まれていません。

注釈

WSAWaitForMultipleEvents 関数は、待機条件が満たされているかどうかを判断します。 条件が満たされていない場合、呼び出し元のスレッドは待機状態になります。 条件が満たされるのを待っている間、プロセッサ時間は使用されません。

WSAWaitForMultipleEvents 関数は、指定したオブジェクトの 1 つまたはすべてをシグナル状態にしたとき、またはタイムアウト間隔が経過したときに返されます。

bWaitAll パラメーターが TRUE の場合、待機操作は、すべてのオブジェクトの状態がシグナルに設定されている場合にのみ完了します。 この関数は、すべてのオブジェクトの状態がシグナルに設定されるまで、指定されたオブジェクトの状態を変更しません。

bWaitAll パラメーターが FALSE の場合、WSAWaitForMultipleEvents は、オブジェクトの 1 つがシグナルされるまで、インデックス 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.1および Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストア アプリでサポートされています。

要件

   
サポートされている最小のクライアント Windows 8.1, Windows Vista [デスクトップ アプリ |UWP アプリ]
サポートされている最小のサーバー Windows Server 2003 [デスクトップ アプリ |UWP アプリ]
対象プラットフォーム Windows
ヘッダー winsock2.h
Library Ws2_32.lib
[DLL] Ws2_32.dll

こちらもご覧ください

標準アクセス権

WSACloseEvent

WSACreateEvent

WaitForMultipleObjectsEx

Winsock 関数

Winsock リファレンス