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 來擷取特定的錯誤號碼。

如同 selectWSAAsyncSelect 函式的情況,經常會使用 WSAEventSelect 來判斷傳送或 recv (傳送recv) 何時可以立即成功。 不過,必須備妥健全的應用程式,以便設定事件物件,併發出會立即傳回 WSAEWOULDBLOCK 的 Windows Sockets 呼叫。 例如,可以執行下列作業順序:

  • 數據抵達套接字 s;Windows Sockets 會設定 WSAEventSelect 事件物件。
  • 應用程式會執行一些其他處理。
  • 處理時,應用程式會發出 ioctlsocket (s、FIONREAD...) ,並注意到已準備好讀取數據。
  • 應用程式會發出 recv (s,...) 来读取数据。
  • 應用程式最後會等候 WSAEventSelect 中指定的事件物件,這會立即傳回,指出數據已準備好讀取。
  • 應用程式會發出 recv (s,...) ,失敗並出現 WSAEWOULDBLOCK 錯誤。
在內部網路事件記錄) 中設定對應的位,併發出相關事件對象的訊號,直到應用程式發出函式呼叫,以隱含重新啟用該網路事件設定併發出相關事件物件的訊號,才能成功記錄發生網路事件 (。
網路事件 重新啟用函式
FD_READ
recv、recvfromWSARecvWSARecvExWSARecvFrom 函式。
FD_WRITE
sendtoWSASendWSASendTo 函式。
FD_OOB
recv、recvfromWSARecvWSARecvExWSARecvFrom 函式。
FD_ACCEPT
除非傳回的錯誤碼WSATRY_AGAIN表示條件函式傳回CF_DEFER,否則 accept、AcceptExWSAAccept 函式除外。
FD_CONNECT
無。
FD_CLOSE
無。
FD_QOS
WSAIoctl 函式與命令SIO_GET_QOS
FD_GROUP_QOS
保留的。
FD_ROUTING_ INTERFACE_CHANGE
具有命令SIO_ROUTING_INTERFACE_CHANGEWSAIoctl 函式。
FD_ADDRESS_ LIST_CHANGE
WSAIoctl 函式與命令SIO_ADDRESS_LIST_CHANGE
 

任何對重新啟用例程的呼叫,甚至是失敗的例程,都會導致重新叫用相關網路事件和事件對象的錄製和訊號。

針對FD_READ,會觸發FD_OOB和FD_ACCEPT網路事件、網路事件錄製和事件物件訊號。 這表示,如果呼叫重新啟用例程,且相關網路條件在呼叫之後仍然有效,則會記錄網路事件,並設定相關聯的事件物件。 這可讓應用程式成為事件驅動,且不擔心任何時間抵達的數據量。 考量以下發生順序:

  1. 傳輸提供者會在套接字 接收 100 個字節的數據,並導致 WS2_32.DLL 記錄FD_READ網路事件並設定相關聯的事件物件。
  2. 應用程式會發出 recv (sbuffptr、50、0) 以讀取 50 個字節。
  3. 傳輸提供者會導致 WS2_32.DLL 記錄FD_READ網路事件,並再次設定相關聯的事件對象,因為仍有要讀取的數據。
使用這些語意時,應用程式不需要讀取所有可用的數據,以回應FD_READ網路事件—適當地回應每個FD_READ網路事件的單一 recv

FD_QOS事件會被視為觸發邊緣。 發生服務質量變更時,只會張貼一次訊息。 除非提供者偵測到服務品質的進一步變更,或應用程式重新交涉套接字的服務質量,否則將不會進行進一步的訊息。

FD_ROUTING_INTERFACE_CHANGE和FD_ADDRESS_LIST_CHANGE事件也會被視為觸發邊緣。 當應用程式要求通知之後,發出 WSAIoctl 並對應 發出SIO_ROUTING_INTERFACE_CHANGESIO_ADDRESS_LIST_CHANGE 來要求通知時,訊息只會張貼一次。 除非應用程式重新發出 IOCTL,且偵測到另一個變更,否則不會傳回其他訊息,因為已發出 IOCTL。

如果應用程式呼叫 WSAEventSelect 或呼叫重新啟用函式時發生網路事件,則會記錄網路事件,並適當地設定相關聯的事件物件。 例如,您可以參考以下兩個序列:

  1. 應用程式會呼叫 接聽
  2. 已收到連線要求,但尚未接受。
  3. 應用程式會呼叫 WSAEventSelect ,指定它對於套接字FD_ACCEPT網路事件感興趣。 由於網路事件的持續性,Windows Sockets 會記錄FD_ACCEPT網路事件,並立即設定相關聯的事件物件。
FD_WRITE網路事件處理方式稍有不同。 當套接字第一次與 connectConnectExWSAConnect、WSAConnectByListWSAConnectByName 函式的呼叫連線時,或接受接受、AcceptExWSAAccept 函式的套接字,然後在傳送失敗且 WSAEWOULDBLOCK 和緩衝區空間變成可用時,就會記錄FD_WRITE網路事件。 因此,應用程式可以假設從第一個FD_WRITE網路事件設定開始傳送,直到傳送傳回 WSAEWOULDBLOCK 為止。 在這類失敗之後,應用程式會發現當記錄FD_WRITE網路事件並設定相關聯的事件物件時,可能會再次傳送。

只有在套接字設定為個別接收 OOB 數據時,才會使用FD_OOB網路事件。 如果套接字設定為內嵌接收 OOB 數據,則會將 OOB (加速) 數據視為一般數據,而且應用程式應該註冊感興趣的數據,而且會取得FD_READ網路事件,而不是FD_OOB網路事件。 應用程式可以使用 setockoptgetsockopt 來設定或檢查要處理 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 記錄和擷取網路活動和錯誤的函式。 請參閱 selectWSAAsyncSelect 的描述,以了解這些函式如何報告網路活動和錯誤。

不論 lNetworkEvents 的值為何,WSAEventSelect 函式都會自動將套接字設定為非封鎖模式。 若要 將套接字設定 回封鎖模式,首先 必須透過呼叫WSAEventSelect 清除與套接字相關聯的事件記錄,並將 lNetworkEvents 設定為零,並將 hEventObject 參數設定為 NULL。 接著,您可以呼叫 ioctlsocketWSAIoctl ,將套接字設定回封鎖模式。

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 會取消相同套接字的任何先前 WSAAsyncSelectWSAEventSelect ,並清除內部網路事件記錄。 例如,若要將事件對象與讀取和寫入網路事件產生關聯,應用程式必須呼叫 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.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

另請參閱

WSAAsyncSelect

WSACloseEvent

WSACreateEvent

WSAEnumNetworkEvents

WSAWaitForMultipleEvents

Winsock 函式

Winsock 參考

shutdown