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
逾時間隔,以毫秒為單位。 WSAWaitForMultipleEvents 如果逾時間隔過期,即使 不符合 fWaitAll 參數所指定的條件,也會傳回 。 如果 dwTimeout 參數為零, WSAWaitForMultipleEvents 會測試指定事件物件的狀態,並立即傳回。 如果 dwTimeoutWSA_INFINITE, WSAWaitForMultipleEvents 會永遠等候;也就是說,逾時間隔永遠不會過期。
[in] fAlertable
值,指定執行緒是否處於可警示的等候狀態,讓系統可執行 I/O 完成常式。 如果 為 TRUE,執行緒會處於可警示的等候狀態, 而 WSAWaitForMultipleEvents 可以在系統執行 I/O 完成常式時傳回。 在此情況下,會傳回 WSA_WAIT_IO_COMPLETION ,而且等候的事件尚未發出訊號。 應用程式必須再次呼叫 WSAWaitForMultipleEvents 函式。 如果 為 FALSE,執行緒就不會處於可警示的等候狀態,而且不會執行 I/O 完成常式。
傳回值
如果 WSAWaitForMultipleEvents 函式成功,則成功時的傳回值是下列其中一個值。
傳回值 | 意義 |
---|---|
|
如果 fWaitAll 參數為 TRUE,則傳回值表示所有指定的事件物件都會發出訊號。
如果 fWaitAll 參數為 FALSE,傳回值減 去WSA_WAIT_EVENT_0 表示符合等候之訊號事件物件的 lphEvents 陣列索引。 如果在呼叫期間收到多個事件物件的訊號,傳回值會指出訊號事件物件的 lphEvents 陣列索引,以及所有訊號事件物件的最小索引值。 |
|
等候已由一或多個已執行的 I/O 完成常式結束。 正在等候的事件尚未發出訊號。 應用程式必須再次呼叫 WSAWaitForMultipleEvents 函式。 只有在 fAlertable 參數為 TRUE時,才能傳回這個傳回值。 |
|
未滿足 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 完成常式時傳回。
執行緒必須處於可警示的等候狀態,系統才能 (非同步程序呼叫或 APC) 執行 I/O 完成常式。 因此,如果應用程式在有 I/O 完成常式且fAlertable參數為FALSE的擱置非同步作業時呼叫WSAWaitForMultipleEvents,即使這些 I/O 作業已完成,也不會執行這些 I/O 完成常式。
如果 fAlertable 參數為 TRUE 且其中一個擱置的作業完成,則會執行 APC, 且 WSAWaitForMultipleEvents 會傳回 WSA_IO_COMPLETION。 暫止事件尚未發出訊號。 應用程式必須再次呼叫 WSAWaitForMultipleEvents 函式。
需要可警示等候狀態的應用程式,而不需要等待任何事件物件發出訊號,都應該使用 Windows SleepEx 函式。
WSAWaitForMultipleEvents的目前實作會呼叫WaitForMultipleObjectsEx函式。
範例程式碼
下列程式碼範例示範如何使用 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 市集應用程式支援此功能,Windows 8.1、Windows Server 2012 R2 及更新版本。
規格需求
最低支援的用戶端 | Windows 8.1、Windows Vista [傳統型應用程式 |UWP 應用程式] |
最低支援的伺服器 | Windows Server 2003 [傳統型應用程式 |UWP 應用程式] |
目標平台 | Windows |
標頭 | winsock2.h |
程式庫 | Ws2_32.lib |
Dll | Ws2_32.dll |