Функция WSAWaitForMultipleEvents (winsock2.h)

Функция WSAWaitForMultipleEvents возвращает, когда один или все указанные объекты событий находятся в состоянии сигнала, по истечении времени ожидания или при выполнении подпрограммы завершения ввода-вывода.

Синтаксис

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

Интервал времени ожидания в миллисекундах. WSAWaitForMultipleEvents возвращает значение, если истекает время ожидания, даже если условия, заданные параметром fWaitAll , не выполнены. Если параметр dwTimeout равен нулю , WSAWaitForMultipleEvents проверяет состояние указанных объектов событий и возвращает немедленно. Если параметр dwTimeoutWSA_INFINITE, WSAWaitForMultipleEvents будет ждать вечно; то есть интервал времени ожидания никогда не истекает.

[in] fAlertable

Значение типа , указывающее, помещается ли поток в состояние ожидания с оповещениями, чтобы система пустила процедуры завершения ввода-вывода. Если задано значение TRUE, поток помещается в состояние ожидания с оповещением, и WSAWaitForMultipleEvents может возвращать данные, когда система выполняет подпрограмму завершения ввода-вывода. В этом случае возвращается WSA_WAIT_IO_COMPLETION , а событие, ожидающее, пока не сообщается. Приложение должно снова вызвать функцию WSAWaitForMultipleEvents . Если значение РАВНО FALSE, поток не помещается в состояние ожидания с оповещениями, а подпрограммы завершения ввода-вывода не выполняются.

Возвращаемое значение

Если функция 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
Ожидание было завершено одной или несколькими подпрограммами завершения ввода-вывода, которые были выполнены. Событие, которое ожидалось, пока не сообщается. Приложение должно снова вызвать функцию WSAWaitForMultipleEvents . Это возвращаемое значение может быть возвращено, только если параметр fAlertable имеет значение TRUE.
WSA_WAIT_TIMEOUT
Истекло время ожидания и условия, заданные параметром fWaitAll , не были выполнены. Подпрограммы завершения ввода-вывода не выполнялись.
 

Если функция 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, операция ожидания завершается только в том случае, если для состояний всех объектов задано значение Signaled. Функция не изменяет состояния указанных объектов до тех пор, пока состояния всех объектов не будут заданы как сигнальные.

Если параметр bWaitAll имеет значение FALSE, WSAWaitForMultipleEvents проверяет дескрипторы в массиве lphEvents в порядке, начиная с индекса 0, пока не будет подан сигнал об одном из объектов. Если несколько объектов становятся сигнальными, функция возвращает индекс первого дескриптора в массиве lphEvents , объект которого был сигнализован.

Эта функция также используется для выполнения оповещенного ожидания, задав для параметра fAlertable значение TRUE. Это позволяет функции возвращать, когда система выполняет подпрограмму завершения ввода-вывода вызывающим потоком.

Поток должен находиться в состоянии ожидания с оповещениями, чтобы система выполняла процедуры завершения ввода-вывода (асинхронные вызовы процедур или APC). Поэтому если приложение вызывает WSAWaitForMultipleEvents при наличии ожидающих асинхронных операций со подпрограммами завершения ввода-вывода и параметром fAlertable является FALSE, эти подпрограммы завершения ввода-вывода не будут выполняться, даже если эти операции ввода-вывода завершены.

Если параметр fAlertable имеет значение TRUE и одна из ожидающих операций завершается, APC выполняется и WSAWaitForMultipleEvents вернет WSA_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 Windows Phone 8 и более поздних версий.

Windows 8.1 и Windows Server 2012 R2: эта функция поддерживается для приложений Магазина Windows на Windows 8.1, Windows Server 2012 R2 и более поздних версий.

Требования

   
Минимальная версия клиента Windows 8.1, Windows Vista [классические приложения | Приложения UWP]
Минимальная версия сервера Windows Server 2003 [классические приложения | Приложения UWP]
Целевая платформа Windows
Header winsock2.h
Библиотека Ws2_32.lib
DLL Ws2_32.dll

См. также раздел

Стандартные права доступа

WSACloseEvent

WSACreateEvent

WaitForMultipleObjectsEx

Функции Winsock

Справочник по Winsock