共用方式為


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 結構的選擇性指標,可接收連線實體的位址,稱為通訊層。 載入宏 參數的確切格式是由建立套接字時建立的位址系列所決定。

[in, out] addrlen

整數的選擇性指標,其中包含 addr 參數所指向之 sockaddr 結構的長度,以位元組為單位。

[in] lpfnCondition

選擇性、應用程式指定條件函式的位址,會根據傳入做為參數的呼叫端資訊做出接受/拒絕決策,並選擇性地將適當的值指派給這個函式的結果參數,g,選擇性地建立或聯結套接字群組。 如果此參數 NULL,則不會呼叫條件函式。

[in] dwCallbackData

回呼數據會傳回至應用程式指定的條件函式,做為傳遞至 condition 函式之 dwCallbackData 參數的值。 只有當 lpfnCondition 參數不 NULL時,此參數才適用。 Windows Sockets 不會解譯此參數。

傳回值

如果沒有發生錯誤,WSAAccept 會傳回 SOCKET 類型的值,這個值是接受套接字的描述項。 否則,會傳回 INVALID_SOCKET的值,而且可以呼叫 WSAGetLastError來擷取特定的錯誤碼。

addrlen 所參考的整數 一開始包含 載入宏所指向的空間量。傳回時,它會包含所傳回位址的實際長度,以位元組為單位。

錯誤碼 意義
WSAEACCES
嘗試以其訪問許可權禁止的方式存取套接字。 如果提供的連線要求已逾時或已撤銷,則會傳回此錯誤。
WSAECONNREFUSED
因為目標計算機主動拒絕連線,所以無法進行連線。 如果連線要求已強制拒絕,如條件函式的傳回值中所指出,則會傳回此錯誤(CF_REJECT)。
WSAECONNRESET
遠端主機強制關閉現有的連線。 已指出傳入連線傳回此錯誤,但在接受呼叫之前,遠端對等已終止。
WSAEFAULT
系統在嘗試在呼叫中使用指標自變數時偵測到無效的指標位址。 這個錯誤會傳回 addrlen 參數太小,或 載入宏lpfnCondition 不是使用者位址空間的一部分。
WSAEINTR
封鎖作業因呼叫 WSACancelBlockingCall而中斷。 如果封鎖的 Windows Sockets 1.1 呼叫已透過 WSACancelBlockingCall 取消,就會傳回此錯誤。
WSAEINPROGRESS
封鎖作業目前正在執行。 如果封鎖的 Windows Sockets 1.1 呼叫正在進行中,就會傳回此錯誤。
WSAEINVAL
已提供無效的自變數。 如果在 WSAAccept之前未叫用 接聽,則會傳回此錯誤,條件函式的傳回值不是有效的,或指定套接字處於無效狀態的任何情況。
WSAEMFILE
太多開啟的套接字。 如果進入 WSAAccept 且沒有可用的套接字描述元,則會傳回此錯誤。
WSAENETDOWN
套接字作業遇到無效的網路。 如果網路子系統失敗,則會傳回此錯誤。
WSAENOBUFS
無法執行套接字上的作業,因為系統沒有足夠的緩衝區空間或佇列已滿。 如果沒有可用的緩衝區空間,則會傳回此錯誤。
WSAENOTSOCK
在不是套接字的某個項目上嘗試作業。 如果傳入 參數的套接字描述元不是套接字,就會傳回此錯誤。
WSAEOPNOTSUPP
通訊協定系列尚未設定到系統中,或不存在其實作。 如果參考的套接字不是支援連線導向服務的型別,則會傳回此錯誤。
WSAEWOULDBLOCK
無法立即完成非封鎖套接字作業。 如果套接字標示為非封鎖,且未接受任何連線,則會傳回此錯誤。
WSANOTINITIALISED
應用程式未呼叫 WSAStartup,或 WSAStartup 失敗。 這個錯誤傳回成功呼叫 WSAStartup 函式 dit 之前未發生。
WSATRY_AGAIN
這通常是主機名解析期間的暫時錯誤,表示本地伺服器未收到來自授權伺服器的回應。 如果接受連接要求已延遲,則會傳回此錯誤,如條件函式的傳回值 (CF_DEFER) 所示。

言論

WSAAccept 函式會擷取套接字 上暫止連線佇列上的第一個連線,並根據條件函式檢查它,前提是指定條件函式(也就是說,不是 NULL)。 如果條件函式傳回CF_ACCEPT,WSAAccept 會建立新的套接字。 新建立的套接字具有與套接字 相同的屬性,包括向 WSAAsyncSelect 註冊的異步事件,或使用 WSAEventSelect。 如果條件函式傳回CF_REJECT,WSAAccept 會拒絕連線要求。 條件函式會在與此函式相同的線程中執行,而且應該儘快傳回。 如果無法立即做出決策,條件函式應該會傳回CF_DEFER,表示尚未做出任何決策,而且服務提供者不應採取任何關於此連線要求的動作。 當應用程式準備好對連線要求採取動作時,它會再次叫用 WSAAccept,並傳回CF_ACCEPT或CF_REJECT作為條件函式的傳回值。

當應用程式呼叫 WSAAccept 且佇列上沒有擱置連線時,預設模式中的套接字將會封鎖(封鎖) 。

當應用程式呼叫 WSAAccept 且佇列上沒有任何連線擱置時,非封鎖模式中的套接字會失敗,且發生錯誤 WSAEWOULDBLOCKWSAAccept 成功並傳回新的套接字句柄之後,就無法再使用接受的套接字來接受任何其他連線。 原始套接字會保持開啟狀態,並接聽新的連線要求。

載入宏 參數是一個結果參數,會填入連線實體的位址,稱為通訊層。 載入宏 參數的確切格式是由通訊發生所在的位址系列所決定。 addrlen 是 value-result 參數;它一開始應該包含 載入宏所指向的空間量,。在傳回時,它會包含所傳回位址的實際長度(以位元組為單位)。 此呼叫會與連線導向的套接字類型搭配使用,例如SOCK_STREAM。 如果 載入宏 和/或 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。 許多網路協定不支援連線時間呼叫端數據。 大部分的傳統網路協定都可以在連線要求時間支援呼叫端標識符資訊。 lpCaller Id 所指向之 WSABUF 的 buf 部分指向 sockaddr襪子 結構會根據其位址系列來解譯(通常是將 襪子 轉換成位址系列特定的某種類型)。

lpSQOS 參數會參考呼叫者所指定套接字 FLOWSPEC 結構,每個方向各有一個,後面接著任何其他提供者特定參數。 針對任何單向套接字,傳送或接收流程規格值將會視需要忽略。 NULL 值表示沒有呼叫端提供的服務品質,而且不可能進行交涉。 非NULLlpSQOS 指標表示會發生服務品質交涉,或提供者準備接受不交涉的服務品質要求。

lpGQOS 參數已保留,且應該 NULL。 (保留供未來搭配套接字群組使用)參考呼叫端所要建立之套接字群組 FLOWSPEC 結構,每個方向各有一個,後面接著任何其他提供者特定參數。 lpGQOS NULL 值表示沒有呼叫端指定的群組服務品質。 如果交涉發生,可以傳回服務質量資訊。

lpCalleeId 是包含連線實體本機地址的參數。 lpCalleeId 所指向的 WSABUF buf 部分 指向 sockaddr 結構。 ockaddr 結構會根據其位址系列來解譯(通常藉由將 襪子 轉換成位址系列特定的某種類型,例如結構 sockaddr_in)。

lpCalleeData 是條件函式用來提供用戶數據給連接實體的結果參數。 lpCalleeData->len 一開始會包含服務提供者所配置的緩衝區長度,並由 lpCalleeData->buf所指向。 值為零表示不支援將用戶數據傳回給呼叫端。 condition 函式應該最多將 lpCalleeData->len 個字節的數據複製到 lpCalleeData->buf,然後更新 lpCalleeData->len,以指出傳輸的實際位元組數目。 如果未將用戶數據傳回給呼叫者,條件函式應該會將 lpCalleeData- >len 設為零。 所有地址和用戶數據的格式都專屬於套接字所屬的位址系列。

條件函式內會指派 g 參數,以指出下列任何動作:

  • 如果 g 是現有的套接字群組標識符,請新增 s 至此群組,前提是符合此群組設定的所有需求。
  • 如果 g = SG_UNCONSTRAINED_GROUP,請建立不受限制的套接字群組,並將 s 作為第一個成員。
  • 如果 g = SG_CONSTRAINED_GROUP,請建立受限制的套接字群組,並將 s 作為第一個成員。
  • 如果 g = 零,則不會執行群組作業。
對於不受限制的群組,只要單一服務提供者支援套接字集,就可以將任何一組套接字群組在一起。 限制的套接字群組只能包含連線導向的套接字,而且要求所有群組套接字上的連線都位於相同主機上的相同位址。 針對新建立的套接字群組,可以使用 getsockopt 函式來擷取新的群組標識符,並將 層級 參數設定為 SOL_SOCKET,並將 optname 參數設定為 SO_GROUP_ID。 套接字群組及其相關聯的套接字群組標識符會維持有效狀態,直到最後一個屬於此套接字群組的套接字關閉為止。 套接字群組標識碼對於指定服務提供者的所有進程而言都是唯一的。 套接字群組及其相關聯的標識符會維持有效狀態,直到最後一個屬於此套接字群組的套接字關閉為止。 套接字群組標識碼對於指定服務提供者的所有進程而言都是唯一的。 如需套接字群組的詳細資訊,請參閱 WSASocket 函式的。

傳遞至 condition 函式 dwCallbackData 參數值是傳遞為原始 WSAAccept 呼叫中 dwCallbackData 參數的值。 這個值只會由 Windows Socket 第 2 版用戶端解譯。 這可讓用戶端將某些內容資訊從 WSAAccept 呼叫月臺傳遞至條件函式。 這也會提供條件函式,並提供判斷是否接受連接所需的任何其他資訊。 典型的用法是將 (適當轉型) 指標傳遞至數據結構,其中包含與這個套接字相關聯之應用程式定義對象的參考。

注意 若要保護使用 WSAAccept 函式免受 SYN 攻擊,應用程式必須先執行完整的 TCP 交握(SYN-SYNACK-ACK),才能報告連線要求。 以這種方式保護 SYN 攻擊會導致SO_CONDITIONAL_ACCEPT套接字選項變得無效:仍會呼叫條件函式,且 WSAAccept 函式會正常運作,但依賴客戶端無法執行交握的伺服器應用程式將無法正常運作。
 
注意 發出封鎖的 Winsock 呼叫時,例如 WSAAccept,Winsock 可能需要等待網路事件,才能完成呼叫。 在此情況下,Winsock 會執行可警示的等候,這可由排程在相同線程上的異步過程調用 (APC) 中斷。 在 APC 內發出另一個封鎖 Winsock 呼叫,中斷相同線程上持續封鎖 Winsock 呼叫會導致未定義的行為,且 Winsock 用戶端絕不能嘗試。
 

範例程序代碼

下列範例示範如何使用 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 Store 應用程式支援Windows Phone 8 和更新版本。

Windows 8.1Windows Server 2012 R2:Windows 8.1、Windows Server 2012 R2 和更新版本上支援 Windows 市集應用程式。

要求

要求 價值
最低支援的用戶端 Windows 8.1、Windows Vista [傳統型應用程式 |UWP 應用程式]
支援的最低伺服器 Windows Server 2003 [傳統型應用程式 |UWP 應用程式]
目標平臺 窗戶
標頭 winsock2.h
連結庫 Ws2_32.lib
DLL Ws2_32.dll

另請參閱

WSAAsyncSelect

WSAConnect

WSASocket

Winsock 函式

Winsock 參考

接受

系結

連線

取得

接聽

選取 [

sockaddr

套接字