WSAAccept 函式 (winsock2.h)
WSAAccept 函式會根據條件函式的傳回值,條件式接受連線、提供服務品質流程規格,並允許傳輸連線數據。
語法
SOCKET WSAAPI WSAAccept(
[in] SOCKET s,
[out] sockaddr *addr,
[in, out] LPINT addrlen,
[in] LPCONDITIONPROC lpfnCondition,
[in] DWORD_PTR dwCallbackData
);
參數
[in] s
描述項,識別在呼叫 接聽 函式之後接聽連線的套接字。
[out] addr
接收連線實體位址的 sockaddr 結構的選擇性指標,稱為通訊層。 addr 參數的確切格式取決於建立套接字時所建立的位址系列。
[in, out] addrlen
整數的選擇性指標,包含 addr 參數所指向之 sockaddr 結構的長度,以位元組為單位。
[in] lpfnCondition
選擇性、應用程式指定的條件函式位址,會根據傳入做為參數的呼叫端資訊做出接受/拒絕決策,並選擇性地將適當的值指派給此函式的結果參數 g ,以建立或聯結套接字群組。 如果此參數為 NULL,則不會呼叫條件函式。
[in] dwCallbackData
傳回至應用程式指定條件函式的回呼數據,做為傳遞至條件函式之 dwCallbackData 參數的值。 只有當 lpfnCondition 參數不是 NULL 時,此參數才適用。 Windows Sockets 不會解譯此參數。
傳回值
如果沒有發生錯誤, WSAAccept 會傳回 SOCKET 類型的值,這是接受套接字的描述項。 否則,會傳回INVALID_SOCKET的值,而且可以呼叫 WSAGetLastError 來擷取特定的錯誤碼。
addrlen 所參考的整數一開始包含 addr 所指向的空間量。傳回時,它會包含所傳回位址的實際長度位元組。
錯誤碼 | 意義 |
---|---|
嘗試透過其訪問許可權禁止的方式來存取套接字。 如果提供的連線要求逾時或已撤銷,就會傳回此錯誤。 | |
因為目標計算機主動拒絕連線,所以無法進行連線。 如果強制拒絕連線要求,則會傳回此錯誤,如條件函式的傳回值所指出 (CF_REJECT) 。 | |
遠端主機已強制關閉一個現有連線。 已指出傳入連線的這個錯誤,但在接受呼叫之前,遠端對等已終止。 | |
系統在嘗試在呼叫中使用指標自變數時偵測到無效的指標位址。 addrlen 參數傳回這個錯誤太小,或者 addr 或 lpfnCondition 不是使用者位址空間的一部分。 | |
封鎖作業因呼叫 WSACancelBlockingCall 而中斷。 如果透過 WSACancelBlockingCall 取消封鎖的 Windows Sockets 1.1 呼叫,就會傳回此錯誤。 | |
正在執行封鎖作業。 如果發生封鎖的 Windows Sockets 1.1 呼叫正在進行,就會傳回此錯誤。 | |
提供的引數無效。 如果在 WSAAccept 之前未叫用接聽、條件函式的傳回值不是有效的值,或指定套接字處於無效狀態的任何情況,就會傳回此錯誤。 | |
太多開啟的套接字。 如果佇列在 進入 WSAAccept 時無空,而且沒有可用的套接字描述元,就會傳回此錯誤。 | |
通訊端作業遇到停止的網路。 如果網路子系統失敗,就會傳回此錯誤。 | |
無法執行套接字上的作業,因為系統缺少足夠的緩衝區空間,或因為佇列已滿。 如果沒有可用的緩衝區空間,就會傳回此錯誤。 | |
嘗試在不是套接字的某個專案上執行作業。 如果傳入 s 參數的套接字描述元不是套接字,就會傳回此錯誤。 | |
通訊協定系列尚未設定為系統,或不存在任何實作。 如果參考的套接字不是支援連線導向服務的型別,就會傳回此錯誤。 | |
無法立即完成非封鎖套接字作業。 如果套接字標示為非封鎖且未接受任何連線,則會傳回此錯誤。 | |
應用程式未呼叫 WSAStartup,或 WSAStartup 失敗。 使用這個函式之前,會傳回成功呼叫 WSAStartup 函式 dit 時,不會發生此錯誤。 | |
這通常為主機名稱解析期間的暫時錯誤,表示本機伺服器未收到授權伺服器的回應。 如果接受連接要求已延遲,則會傳回此錯誤,如條件函式的傳回值所示 (CF_DEFER) 。 |
備註
WSAAccept 函式會擷取套接字上擱置連線佇列上的第一個連線,並根據條件函式檢查它,前提是條件函式已指定為 (,而不是 NULL) 。 如果條件函式傳回 CF_ACCEPT,WSAAccept 會建立新的套接字。 新建立的套接字具有與套接字 相同的屬性, 包括向 WSAAsyncSelect 或 WSAEventSelect 註冊的異步事件。 如果條件函式傳回 CF_REJECT,WSAAccept 會拒絕連線要求。 條件函式會在與此函式相同的線程中執行,而且應該儘快傳回。 如果無法立即做出決策,條件函式應該會傳回CF_DEFER,以指出尚未做出任何決策,而且服務提供者不應該採取此連線要求的任何動作。 當應用程式準備好對連線要求採取動作時,它會再次叫用 WSAAccept ,並傳回CF_ACCEPT或CF_REJECT作為條件函式的傳回值。
默認模式中的套接字 (封鎖) 會封鎖,直到應用程式呼叫 WSAAccept 且佇列上沒有任何連線擱置為止。
非封鎖模式中的套接字 (封鎖) 失敗,當應用程式呼叫 WSAAccept 且佇列上沒有任何連線擱置時發生 WSAEWOULDBLOCK 錯誤。 WSAAccept 成功並傳回新的套接字句柄之後,無法再使用接受的套接字來接受任何連線。 原始套接字會保持開啟狀態,並接聽新的連線要求。
addr 參數是填入連線實體位址的結果參數,稱為通訊層。 addr 參數的確切格式是由通訊發生的位址系列所決定。 addrlen 是 value-result 參數;它一開始應該包含附加元件所指向的空間量。傳回時,它會包含所傳回位址) 以位元組為單位的實際長度 (。 此呼叫會與連線導向的套接字類型搭配使用,例如 SOCK_STREAM。 如果 addr 和/或 addrlen 等於 NULL,則不會傳回所接受套接字遠端地址的相關信息。 否則,如果成功接受連線,則會填入這兩個參數。
條件函式的原型會在頭檔中定義為 Winsock2.h
LPCONDITIONPROC,如下所示。
int CALLBACK
ConditionFunc(
IN LPWSABUF lpCallerId,
IN LPWSABUF lpCallerData,
IN OUT LPQOS lpSQOS,
IN OUT LPQOS lpGQOS,
IN LPWSABUF lpCalleeId,
IN LPWSABUF lpCalleeData,
OUT GROUP FAR * g,
IN DWORD_PTR dwCallbackData
);
ConditionFunc 是應用程式指定回呼函式的佔位符。 實際條件函式必須位於 DLL 或應用程式模組中。 它會在模組定義檔中匯出。
lpCallerId 參數指向 WSABUF 結構,其中包含連接實體的位址,其中其 len 參數是位元組的緩衝區長度,而其 buf 參數是緩衝區的指標。 lpCallerData 是包含任何用戶數據的值參數。 這些參數中的資訊會連同連線要求一起傳送。 如果沒有呼叫端識別或呼叫端數據可用,對應的參數會是 NULL。 許多網路協定不支援連線時間呼叫端數據。 大部分的傳統網路協定都可以在連線要求時間支援呼叫端標識符資訊。 lpCallerId 所指向 WSABUF 的 buf 部分指向 sockaddr。 sockaddr 結構會根據其位址系列解譯, (通常是藉由將sockaddr轉換成位址系列特定的某些類型) 。
lpSQOS 參數會參考呼叫端所指定套接字的FLOWSPEC 結構,每個方向各有一個,後面接著任何其他提供者特定參數。 傳送或接收流程規格值會視情況忽略任何單向套接字。 NULL 值表示沒有呼叫端提供的服務品質,而且不可能進行交涉。 非 NULLlpSQOS 指標表示要進行服務品質交涉,或提供者已準備好接受沒有交涉的服務品質要求。
lpGQOS 參數是保留的,而且應該是 NULL。 (保留給未來與套接字群組搭配使用,) 參考呼叫端所要建立之套接字群組 的 FLOWSPEC 結構,每個方向各有一個,後面接著任何其他提供者特定參數。 lpGQOS 的 NULL 值表示沒有呼叫端指定的群組服務品質。 如果交涉發生,則可以傳回服務質量資訊。
lpCalleeId 是包含連線實體之本機地址的參數。 由 lpCalleeId 指向之 WSABUF 的 buf 部分指向 sockaddr 結構。 sockaddr 結構會根據其位址系列來解譯 (通常是藉由將sockaddr轉換成位址系列的特定類型,例如結構sockaddr_in) 。
lpCalleeData 是條件函式用來提供用戶數據給連接實體的結果參數。 lpCalleeData-len> 最初包含服務提供者配置的緩衝區長度,並由 lpCalleeData-buf> 指向。 值為零表示不支援將用戶數據傳回給呼叫端。 condition 函式應該最多將 lpCalleeData-len 位元組的數據複製到 lpCalleeData-buf>>,然後更新 lpCalleeData-len>,以指出傳送的實際位元組數目。 如果未將用戶數據傳回給呼叫端,條件函式應該會將 lpCalleeData-len> 設定為零。 所有地址和用戶數據的格式都專屬於套接字所屬的位址系列。
g 參數會在 condition 函式內指派,以指出下列任何動作:
- 如果 g 是現有的套接字群組標識符 ,請將 新增 至此群組,前提是符合此群組設定的所有需求。
- 如果 g = SG_UNCONSTRAINED_GROUP,請建立不受限制的套接字群組,並將 設為 第一個成員。
- 如果 g = SG_CONSTRAINED_GROUP,請建立受限制的套接字群組,並具有 作為 第一個成員。
- 如果 g = 零,則不會執行任何群組作業。
傳遞至 condition 函式的 dwCallbackData 參數值,是在原始 WSAAccept 呼叫中當做 dwCallbackData 參數傳遞的值。 這個值只會由 Windows Socket 第 2 版用戶端解譯。 這可讓客戶端將 來自 WSAAccept 呼叫網站的一些內容資訊傳遞至條件函式。 這也會提供條件函式,並提供判斷是否接受連接所需的任何其他資訊。 典型的用法是傳遞 (適當地轉換) 指標至包含與此套接字相關聯之應用程式定義對象的參考的數據結構。
範例程序代碼
下列範例示範 如何使用 WSAAccept 函 式。#include <winsock2.h>
#include <stdio.h>
#include <windows.h>
/* Define an example conditional function that depends on the pQos field */
int CALLBACK ConditionAcceptFunc(
LPWSABUF lpCallerId,
LPWSABUF lpCallerData,
LPQOS pQos,
LPQOS lpGQOS,
LPWSABUF lpCalleeId,
LPWSABUF lpCalleeData,
GROUP FAR * g,
DWORD_PTR dwCallbackData
)
{
if (pQos != NULL) {
RtlZeroMemory(pQos, sizeof(QOS));
return CF_ACCEPT;
} else
return CF_REJECT;
}
int main() {
/* Declare and initialize variables */
WSADATA wsaData;
SOCKET ListenSocket, AcceptSocket;
struct sockaddr_in saClient;
int iClientSize = sizeof(saClient);
u_short port = 27015;
char* ip;
sockaddr_in service;
int error;
/* Initialize Winsock */
error = WSAStartup(MAKEWORD(2,2), &wsaData);
if (error) {
printf("WSAStartup() failed with error: %d\n", error);
return 1;
}
/* Create a TCP listening socket */
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
printf("socket() failed with error: %d\n", WSAGetLastError() );
WSACleanup();
return 1;
}
/*-----------------------------------------
* Set up the sock addr structure that the listening socket
* will be bound to. In this case, the structure holds the
* local IP address and the port specified. */
service.sin_family = AF_INET;
service.sin_port = htons(port);
hostent* thisHost;
thisHost = gethostbyname("");
ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
service.sin_addr.s_addr = inet_addr(ip);
/*-----------------------------------------
* Bind the listening socket to the IP address.
* and port number specified by the sockaddr structure. */
error = bind(ListenSocket, (SOCKADDR *) &service, sizeof(SOCKADDR));
if (error == SOCKET_ERROR) {
printf("bind() failed with error: %d\n", WSAGetLastError() );
closesocket(ListenSocket);
WSACleanup();
return 1;
}
/* Make the socket listen for incoming connection requests */
error = listen(ListenSocket, 1);
if (error == SOCKET_ERROR) {
printf("listen() failed with error: %d\n", WSAGetLastError() );
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf("Listening...\n");
/*-----------------------------------------
* Accept an incoming connection request on the
* listening socket and transfer control to the
* accepting socket. */
AcceptSocket = WSAAccept(ListenSocket, (SOCKADDR*) &saClient, &iClientSize,
&ConditionAcceptFunc, NULL);
/* Now do some work with the AcceptSocket
* At this point, the application could
* handle data transfer on the socket, or other socket
* functionality.*/
/* Then clean up and quit */
closesocket(AcceptSocket);
closesocket(ListenSocket);
WSACleanup();
return 0;
}
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 |
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將推出:在 2024 年,我們將隨著內容的意見反應機制逐步淘汰 GitHub 問題,並以新的意見反應系統來取代。 如需詳細資訊,請參閱提交並檢視相關的意見反應