WSAEventSelect 函式 (winsock2.h)
WSAEventSelect 函式會指定要與指定之一組FD_XXX網路事件相關聯的事件物件。
語法
int WSAAPI WSAEventSelect(
[in] SOCKET s,
[in] WSAEVENT hEventObject,
[in] long lNetworkEvents
);
參數
[in] s
識別套接字的描述項。
[in] hEventObject
句柄,識別要與指定之一組FD_XXX網路事件相關聯的事件物件。
[in] lNetworkEvents
位掩碼,指定應用程式感興趣的FD_XXX網路事件組合。
傳回值
如果應用程式的網路事件規格和相關聯的事件物件成功,則傳回值為零。 否則,會傳回SOCKET_ERROR值,並呼叫 WSAGetLastError 來擷取特定的錯誤號碼。
如同 select 和 WSAAsyncSelect 函式的情況,經常會使用 WSAEventSelect 來判斷傳送或 recv (傳送 或 recv) 何時可以立即成功。 不過,必須備妥健全的應用程式,以便設定事件物件,併發出會立即傳回 WSAEWOULDBLOCK 的 Windows Sockets 呼叫。 例如,可以執行下列作業順序:
- 數據抵達套接字 s;Windows Sockets 會設定 WSAEventSelect 事件物件。
- 應用程式會執行一些其他處理。
- 處理時,應用程式會發出 ioctlsocket (s、FIONREAD...) ,並注意到已準備好讀取數據。
- 應用程式會發出 recv (s,...) 来读取数据。
- 應用程式最後會等候 WSAEventSelect 中指定的事件物件,這會立即傳回,指出數據已準備好讀取。
- 應用程式會發出 recv (s,...) ,失敗並出現 WSAEWOULDBLOCK 錯誤。
網路事件 | 重新啟用函式 |
---|---|
|
recv、recvfrom、WSARecv、WSARecvEx 或 WSARecvFrom 函式。 |
|
sendto、WSASend 或 WSASendTo 函式。 |
|
recv、recvfrom、WSARecv、WSARecvEx 或 WSARecvFrom 函式。 |
|
除非傳回的錯誤碼WSATRY_AGAIN表示條件函式傳回CF_DEFER,否則 accept、AcceptEx 或 WSAAccept 函式除外。 |
|
無。 |
|
無。 |
|
WSAIoctl 函式與命令SIO_GET_QOS。 |
|
保留的。 |
|
具有命令SIO_ROUTING_INTERFACE_CHANGE的 WSAIoctl 函式。 |
|
WSAIoctl 函式與命令SIO_ADDRESS_LIST_CHANGE。 |
任何對重新啟用例程的呼叫,甚至是失敗的例程,都會導致重新叫用相關網路事件和事件對象的錄製和訊號。
針對FD_READ,會觸發FD_OOB和FD_ACCEPT網路事件、網路事件錄製和事件物件訊號。 這表示,如果呼叫重新啟用例程,且相關網路條件在呼叫之後仍然有效,則會記錄網路事件,並設定相關聯的事件物件。 這可讓應用程式成為事件驅動,且不擔心任何時間抵達的數據量。 考量以下發生順序:
- 傳輸提供者會在套接字 接收 100 個字節的數據,並導致 WS2_32.DLL 記錄FD_READ網路事件並設定相關聯的事件物件。
- 應用程式會發出 recv (s、 buffptr、50、0) 以讀取 50 個字節。
- 傳輸提供者會導致 WS2_32.DLL 記錄FD_READ網路事件,並再次設定相關聯的事件對象,因為仍有要讀取的數據。
FD_QOS事件會被視為觸發邊緣。 發生服務質量變更時,只會張貼一次訊息。 除非提供者偵測到服務品質的進一步變更,或應用程式重新交涉套接字的服務質量,否則將不會進行進一步的訊息。
FD_ROUTING_INTERFACE_CHANGE和FD_ADDRESS_LIST_CHANGE事件也會被視為觸發邊緣。 當應用程式要求通知之後,發出 WSAIoctl 並對應 發出SIO_ROUTING_INTERFACE_CHANGE 或 SIO_ADDRESS_LIST_CHANGE 來要求通知時,訊息只會張貼一次。 除非應用程式重新發出 IOCTL,且偵測到另一個變更,否則不會傳回其他訊息,因為已發出 IOCTL。
如果應用程式呼叫 WSAEventSelect 或呼叫重新啟用函式時發生網路事件,則會記錄網路事件,並適當地設定相關聯的事件物件。 例如,您可以參考以下兩個序列:
- 應用程式會呼叫 接聽。
- 已收到連線要求,但尚未接受。
- 應用程式會呼叫 WSAEventSelect ,指定它對於套接字FD_ACCEPT網路事件感興趣。 由於網路事件的持續性,Windows Sockets 會記錄FD_ACCEPT網路事件,並立即設定相關聯的事件物件。
只有在套接字設定為個別接收 OOB 數據時,才會使用FD_OOB網路事件。 如果套接字設定為內嵌接收 OOB 數據,則會將 OOB (加速) 數據視為一般數據,而且應用程式應該註冊感興趣的數據,而且會取得FD_READ網路事件,而不是FD_OOB網路事件。 應用程式可以使用 setockopt 或 getsockopt 來設定或檢查要處理 OOB 資料的方式,以取得SO_OOBINLINE選項。
FD_CLOSE網路事件中的錯誤碼會指出套接字關閉是否正常或中止。 如果錯誤碼為零,則關閉正常;如果錯誤碼為 WSAECONNRESET,則套接字的虛擬線路已重設。 這隻適用於連線導向套接字,例如 SOCK_STREAM。
當收到對應至套接字之虛擬線路的關閉指示時,就會記錄FD_CLOSE網路事件。 在 TCP 詞彙中,這表示當連線進入 TIME WAIT 或 CLOSE WAIT 狀態時,會記錄FD_CLOSE。 這會導致遠端端在傳送端或 closesocket 上執行關機。 FD_CLOSE從套接字讀取所有數據之後張貼。 應用程式應該在收到FD_CLOSE時檢查剩餘的數據,以避免遺失數據的可能性。 如需詳細資訊,請參閱正常關機、Linger 選項和套接字關閉和關機函式一節。
請注意,Windows Sockets 只會記錄FD_CLOSE網路事件,以表示虛擬線路關閉。 它不會記錄FD_READ網路事件來指出此狀況。
當流量規格中的任何參數 與套接字相關聯時,就會記錄FD_QOS或FD_GROUP_QOS網路事件。 應用程式應該使用 WSAIoctl 搭配命令 SIO_GET_QOS ,以取得套接字 的目前服務品質。
FD_ROUTING_INTERFACE_CHANGE網路事件會在發出這類 IOCTL 之後,用來連線 WSAIoctl 中指定的目的地時,會記錄 SIO_ROUTING_INTERFACE_CHANGE FD_ROUTING_INTERFACE_CHANGE 網路事件。
當發出 WSAIoctl 與 SIO_ADDRESS_LIST_CHANGE 之後,應用程式可系結變更的套接字通訊協定系列清單時,就會記錄 FD_ADDRESS_LIST_CHANGE 網路事件。
錯誤碼 | 意義 |
---|---|
WSANOTINITIALISED | 使用這個函式之前,必須先進行成功的 WSAStartup 呼叫。 |
WSAENETDOWN | 網路子系統失敗。 |
WSAEINVAL | 其中一個指定的參數無效,或指定的套接字處於無效狀態。 |
WSAEINPROGRESS | 封鎖的 Windows Sockets 1.1 呼叫正在進行中,或服務提供者仍在處理回呼函式。 |
WSAENOTSOCK | 描述項不是套接字。 |
備註
WSAEventSelect 函式是用來指定事件物件 hEventObject,以與選取 FD_XXX的網路事件 lNetworkEvents 相關聯。 指定事件物件的套接字是由 s 參數識別。 當發生任何指定的網路事件時,就會設定事件物件。
WSAEventSelect 函式的運作方式與 WSAAsyncSelect 非常類似,差異在於指定的網路事件發生時所採取的動作。 WSAAsyncSelect 函式會導致張貼應用程式指定的 Windows 訊息。 WSAEventSelect 會設定相關聯的事件物件,並記錄內部網路事件記錄中發生此事件。 應用程式可以使用 WSAWaitForMultipleEvents 來等候或輪詢事件物件,並使用 WSAEnumNetworkEvents 來擷取內部網路事件記錄的內容,進而判斷已發生的指定網路事件。
重設與 WSAEventSelect 函式搭配使用之事件對象狀態的適當方式,就是將事件物件的句柄傳遞至 hEventObject 參數中的 WSAEnumNetworkEvents 函式。 這會重設事件物件,並以不可部分完成的方式調整套接字上作用中 FD 事件的狀態。
WSAEventSelect 是唯一會導致透過 WSAEnumNetworkEvents 記錄和擷取網路活動和錯誤的函式。 請參閱 select 和 WSAAsyncSelect 的描述,以了解這些函式如何報告網路活動和錯誤。
不論 lNetworkEvents 的值為何,WSAEventSelect 函式都會自動將套接字設定為非封鎖模式。 若要 將套接字設定 回封鎖模式,首先 必須透過呼叫WSAEventSelect 清除與套接字相關聯的事件記錄,並將 lNetworkEvents 設定為零,並將 hEventObject 參數設定為 NULL。 接著,您可以呼叫 ioctlsocket 或 WSAIoctl ,將套接字設定回封鎖模式。
lNetworkEvents 參數是使用位 OR 運算子搭配下列清單中指定的任何值來建構。
值 | 意義 |
---|---|
FD_READ | 想要接收整備程度通知以供閱讀。 |
FD_WRITE | 想要接收寫入整備的通知。 |
FD_OOB | 想要接收 OOB 數據抵達的通知。 |
FD_ACCEPT | 想要接收連入連線的通知。 |
FD_CONNECT | 想要接收已完成連線或多點聯結作業的通知。 |
FD_CLOSE | 想要接收套接字關閉的通知。 |
FD_QOS | 想要接收套接字 (QoS 變更的通知。 |
FD_GROUP_QOS | 保留供未來與套接字群組搭配使用。 想要接收套接字群組 QoS 變更的通知。 |
FD_ROUTING_ INTERFACE_CHANGE | 想要接收指定目的地路由介面變更的通知。 |
FD_ADDRESS_ LIST_CHANGE | 想要接收套接字位址系列之本機通訊清單變更的通知。 |
發出 套接字的 WSAEventSelect 會取消相同套接字的任何先前 WSAAsyncSelect 或 WSAEventSelect ,並清除內部網路事件記錄。 例如,若要將事件對象與讀取和寫入網路事件產生關聯,應用程式必須呼叫 WSAEventSelect 與 FD_READ 和 FD_WRITE,如下所示:
rc = WSAEventSelect(s, hEventObject, FD_READ|FD_WRITE);
無法為不同的網路事件指定不同的事件物件。 下列程式代碼將無法運作;第二個呼叫會取消第一個呼叫的效果,而且只有FD_WRITE網路事件會與 hEventObject2 相關聯:
rc = WSAEventSelect(s, hEventObject1, FD_READ);
rc = WSAEventSelect(s, hEventObject2, FD_WRITE); //bad
若要取消套接字上網路事件的關聯和選取, lNetworkEvents 應該設定為零,在此情況下,將會忽略 hEventObject 參數。
rc = WSAEventSelect(s, hEventObject, 0);
關閉具有 closesocket 的套接字也會取消套接字在 WSAEventSelect 中指定的網路事件關聯和選取。 不過,應用程式仍然必須呼叫 WSACloseEvent ,以明確關閉事件對象並釋放任何資源。
呼叫 accept 函式時所建立的套接字具有與用來接受它的接聽套接字相同的屬性。 針對接聽套接字設定的任何 WSAEventSelect 關聯和網路事件選取範圍都會套用至接受的套接字。 例如,如果接聽套接字具有 hEventObject 與 FD_ACCEPT、FD_READ 和 FD_WRITE 的 WSAEventSelect 關聯,則該接聽套接字上接受的任何套接字也會有與相同 hEventObject 相關聯的FD_ACCEPT、FD_READ和FD_WRITE網路事件。 如果需要不同的 hEventObject 或網路事件,應用程式應該呼叫 WSAEventSelect,並傳遞接受的套接字和所需的新資訊。
範例程序代碼
下列範例示範 如何使用 WSAEventSelect 函式。//-------------------------
// Declare and initialize variables
SOCKET ListenSocket;
WSAEVENT NewEvent;
sockaddr_in InetAddr;
//-------------------------
// Initialize listening socket
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//-------------------------
// Bind listening socket
InetAddr.sin_family = AF_INET;
InetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InetAddr.sin_port = htons(27015);
bind (ListenSocket, (SOCKADDR *) &InetAddr, sizeof(InetAddr));
//-------------------------
// Create new event
NewEvent = WSACreateEvent();
//-------------------------
// Associate event types FD_ACCEPT and FD_CLOSE
// with the listening socket and NewEvent
WSAEventSelect( ListenSocket, NewEvent, FD_ACCEPT | FD_CLOSE);
//----------------------
// Listen for incoming connection requests
// on the created socket
if (listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR)
printf("Error listening on socket.\n");
printf("Listening on socket...\n");
// Need an event handler added to handle connection requests
Windows Phone 8:Windows Phone 8 和更新版本上的 Windows Phone Store 應用程式支援此函式。
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 |
程式庫 | Ws2_32.lib |
Dll | Ws2_32.dll |