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

listen 함수를 호출한 후 연결을 수신 대기하는 소켓을 식별하는 설명자입니다.

[out] addr

통신 계층에 알려진 연결 엔터티의 주소를 수신하는 sockaddr 구조체에 대한 선택적 포인터입니다. addr 매개 변수의 정확한 형식은 소켓을 만들 때 설정된 주소 패밀리에 의해 결정됩니다.

[in, out] addrlen

addr 매개 변수가 가리키는 sockaddr 구조체의 길이를 바이트 단위로 포함하는 정수에 대한 선택적 포인터입니다.

[in] lpfnCondition

매개 변수로 전달된 호출자 정보에 따라 수락/거부 결정을 내리고 필요에 따라 이 함수의 결과 매개 변수 g 에 적절한 값을 할당하여 소켓 그룹을 만들거나 조인하는 선택적 애플리케이션 지정 조건 함수의 주소입니다. 이 매개 변수가 NULL이면 조건 함수가 호출되지 않습니다.

[in] dwCallbackData

조건 함수에 전달된 dwCallbackData 매개 변수 값으로 애플리케이션에서 지정한 조건 함수로 다시 전달된 콜백 데이터입니다. 이 매개 변수는 lpfnCondition 매개 변수가 NULL이 아닌 경우에만 적용됩니다. 이 매개 변수는 Windows 소켓에서 해석되지 않습니다.

반환 값

오류가 발생하지 않으면 WSAAccept 는 허용되는 소켓에 대한 설명자인 SOCKET 형식의 값을 반환합니다. 그렇지 않으면 INVALID_SOCKET 값이 반환되고 WSAGetLastError를 호출하여 특정 오류 코드를 검색할 수 있습니다.

addrlen에서 참조하는 정수에는 처음에 addrlen이 가리키는 공간의 양이 포함됩니다. 반환하면 반환된 주소의 실제 길이(바이트)가 포함됩니다.

오류 코드 의미
WSAEACCES
액세스 권한에 의해 금지된 방식으로 소켓에 액세스하려고 시도했습니다. 제공된 연결 요청 시간이 초과되었거나 철회된 경우 이 오류가 반환됩니다.
WSAECONNREFUSED
대상 컴퓨터에서 연결을 거부했으므로 연결하지 못했습니다. 이 오류는 조건 함수(CF_REJECT)의 반환 값에 표시된 대로 연결 요청이 강제로 거부된 경우 반환됩니다.
WSAECONNRESET
현재 연결은 원격 호스트에 의해 강제로 끊겼습니다. 이 오류는 들어오는 연결에서 반환되었지만 호출을 수락하기 전에 원격 피어에 의해 종료되었습니다.
WSAEFAULT
시스템이 호출에서 포인터 인수를 사용하려는 시도에서 잘못된 포인터 주소를 발견했습니다. addrlen 매개 변수가 너무 작거나 addr 또는 lpfnCondition이 사용자 주소 공간의 일부가 아닌 경우 이 오류가 반환됩니다.
WSAEINTR
WSACancelBlockingCall 호출로 인해 차단 작업이 중단되었습니다. 이 오류는 WSACancelBlockingCall을 통해 차단 Windows 소켓 1.1 호출이 취소된 경우 반환됩니다.
WSAEINPROGRESS
차단 작업이 진행 중입니다. 차단 Windows Sockets 1.1 호출이 진행 중인 경우 이 오류가 반환됩니다.
WSAEINVAL
잘못된 인수가 지정되었습니다. 이 오류는 수신 대기WSAAccept 이전에 호출되지 않았거나, 조건 함수의 반환 값이 유효한 값이 아니거나, 지정된 소켓이 잘못된 상태인 경우에 반환됩니다.
WSAEMFILE
열린 소켓이 너무 많습니다. 이 오류는 WSAAccept 에 진입할 때 큐가 흠잡을 데 없이 사용 가능한 소켓 설명자가 없는 경우 반환됩니다.
WSAENETDOWN
소켓 작업에서 작동하지 않는 네트워크가 검색되었습니다. 이 오류는 네트워크 하위 시스템이 실패한 경우 반환됩니다.
WSAENOBUFS
시스템에 충분한 버퍼 공간이 부족하거나 큐가 가득 차서 소켓에서 작업을 수행할 수 없습니다. 버퍼 공간을 사용할 수 없는 경우 이 오류가 반환됩니다.
WSAENOTSOCK
소켓이 아닌 항목에서 작업을 시도했습니다. 이 오류는 s 매개 변수에 전달된 소켓 설명자가 소켓이 아닌 경우 반환됩니다.
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를 호출하고 큐에 연결이 보류 중이 아닌 경우 비블로킹 모드(차단)의 소켓이 WSAEWOULDBLOCK 오류와 함께 실패합니다. WSAAccept가 성공하고 새 소켓 핸들을 반환한 후에는 허용된 소켓을 사용하여 더 이상 연결을 수락할 수 없습니다. 원래 소켓은 열린 상태로 유지되며 새 연결 요청을 수신 대기합니다.

addr 매개 변수는 통신 계층에 알려진 연결 엔터티의 주소로 채워진 결과 매개 변수입니다. addr 매개 변수의 정확한 형식은 통신이 발생하는 주소 패밀리에 의해 결정됩니다. addrlen은 값 결과 매개 변수입니다. 처음에는 addr가 가리키는 공간의 양을 포함해야 합니다. 반환할 때 반환된 주소의 실제 길이(바이트)를 포함합니다. 이 호출은 SOCK_STREAM 같은 연결 지향 소켓 유형에 사용됩니다. addr 및/또는 addrlenNULL과 같으면 허용된 소켓의 원격 주소에 대한 정보가 반환되지 않습니다. 그렇지 않으면 연결이 성공적으로 수락되면 이러한 두 매개 변수가 채워집니다.

조건 함수의 프로토타입은 헤더 파일에 다음과 같이 LPCONDITIONPROC로 정의 Winsock2.h 됩니다.

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는 모든 사용자 데이터를 포함하는 값 매개 변수입니다. 이러한 매개 변수의 정보는 연결 요청과 함께 전송됩니다. 호출자 ID 또는 호출자 데이터를 사용할 수 없는 경우 해당 매개 변수는 NULL이 됩니다. 대부분의 네트워크 프로토콜은 연결 시간 호출자 데이터를 지원하지 않습니다. 대부분의 기존 네트워크 프로토콜은 연결 요청 시간에 호출자 식별자 정보를 지원할 것으로 예상할 수 있습니다. lpCallerId가 가리키는 WSABUF의 buf 부분은 sockaddr를 가리킵니다. sockaddr 구조체는 주소 패밀리에 따라 해석됩니다(일반적으로 sockaddr를 주소 패밀리와 관련된 일부 형식으로 캐스팅).

lpSQOS 매개 변수는 호출자가 지정한 소켓 대해 FLOWSPEC 구조를 참조하며, 각 방향에 대해 하나씩, 추가 공급자별 매개 변수를 참조합니다. 전송 또는 수신 흐름 사양 값은 단방향 소켓에 대해 적절하게 무시됩니다. NULL 값은 호출자가 제공하는 서비스 품질이 없으며 협상이 가능하지 않음을 나타냅니다. NULL이 아닌 lpSQOS 포인터는 서비스 품질 협상이 발생하거나 공급자가 협상 없이 서비스 품질 요청을 수락할 준비가 되었음을 나타냅니다.

lpGQOS 매개 변수는 예약되어 있으며 NULL이어야 합니다. (소켓 그룹과 함께 나중에 사용하기 위해 예약됨)은 호출자가 만들 소켓 그룹에 대한 FLOWSPEC 구조를 각 방향에 대해 하나씩, 그리고 추가 공급자별 매개 변수를 참조합니다. lpGQOS에 대한 NULL 값은 호출자가 지정한 서비스 그룹 품질을 나타내지 않습니다. 협상이 이루어지는 경우 서비스 품질 정보를 반환할 수 있습니다.

lpCalleeId는 연결된 엔터티의 로컬 주소를 포함하는 매개 변수입니다. lpCalleeId가 가리키는 WSABUF의 buf 부분은 sockaddr 구조를 가리킵니다. sockaddr 구조체는 주소 패밀리에 따라 해석됩니다(일반적으로 sockaddr를 구조체 sockaddr_in 같은 주소 패밀리와 관련된 일부 형식으로 캐스팅).

lpCalleeData는 조건 함수에서 사용자 데이터를 연결 엔터티에 다시 제공하는 데 사용하는 결과 매개 변수입니다. lpCalleeData-len>은 처음에 서비스 공급자가 할당하고 lpCalleeData-buf>가 가리키는 버퍼의 길이를 포함합니다. 값이 0이면 사용자 데이터를 호출자에게 다시 전달하는 것은 지원되지 않습니다. 조건 함수는 lpCalleeData-len 바이트의 데이터를 lpCalleeData-buf>로 복사한 다음 lpCalleeData-len>을 업데이트하여 전송된 실제 바이트 수를 표시해야 합니다.> 호출자에게 다시 전달할 사용자 데이터가 없는 경우 조건 함수는 lpCalleeData-len>을 0으로 설정해야 합니다. 모든 주소 및 사용자 데이터의 형식은 소켓이 속한 주소 패밀리에 따라 다릅니다.

g 매개 변수는 다음 작업을 나타내기 위해 조건 함수 내에 할당됩니다.

  • g가 기존 소켓 그룹 식별자인 경우 이 그룹에서 설정한 모든 요구 사항이 충족되면 이 그룹에 s를 추가합니다.
  • g = SG_UNCONSTRAINED_GROUP 경우 제약이 없는 소켓 그룹을 만들고 첫 번째 멤버로 사용합니다.
  • g = SG_CONSTRAINED_GROUP 경우 제한된 소켓 그룹을 만들고 첫 번째 멤버로 사용합니다.
  • g = 0이면 그룹 작업이 수행되지 않습니다.
제한되지 않은 그룹의 경우 단일 서비스 공급자가 지원하는 한 소켓 집합을 함께 그룹화할 수 있습니다. 제한된 소켓 그룹은 연결 지향 소켓으로만 구성될 수 있으며 모든 그룹화된 소켓의 연결이 동일한 호스트의 동일한 주소에 연결되어야 합니다. 새로 만든 소켓 그룹의 경우 수준 매개 변수가 SOL_SOCKET 설정되고 optname 매개 변수가 SO_GROUP_ID 설정된 getsockopt함수를 사용하여 새 그룹 식별자를 검색할 수 있습니다. 소켓 그룹 및 관련 소켓 그룹 ID는 이 소켓 그룹에 속한 마지막 소켓이 닫혀 있을 때까지 유효한 상태로 유지됩니다. 소켓 그룹 ID는 지정된 서비스 공급자에 대한 모든 프로세스에서 고유합니다. 소켓 그룹과 연결된 식별자는 이 소켓 그룹에 속한 마지막 소켓이 닫혀 있을 때까지 유효한 상태를 유지합니다. 소켓 그룹 식별자는 지정된 서비스 공급자에 대한 모든 프로세스에서 고유합니다. 소켓 그룹에 대한 자세한 내용은 WSASocket 함수에 대한 설명을 참조하세요.

조건 함수에 전달된 dwCallbackData 매개 변수 값은 원래 WSAAccept 호출에서 dwCallbackData 매개 변수로 전달되는 값입니다. 이 값은 Windows 소켓 버전 2 클라이언트에서만 해석됩니다. 이렇게 하면 클라이언트가 WSAAccept 호출 사이트에서 조건 함수로 일부 컨텍스트 정보를 전달할 수 있습니다. 또한 연결 허용 여부를 결정하는 데 필요한 추가 정보를 조건 함수에 제공합니다. 일반적인 사용법은 이 소켓이 연결된 애플리케이션 정의 개체에 대한 참조가 포함된 데이터 구조에 (적절하게 캐스팅된) 포인터를 전달하는 것입니다.

참고SYN 공격으로부터 WSAAccept 함수의 사용을 보호하려면 애플리케이션은 연결 요청을 보고하기 전에 전체 TCP 핸드셰이크(SYN-SYNACK-ACK)를 수행해야 합니다. 이러한 방식으로 SYN 공격으로부터 보호하면 SO_CONDITIONAL_ACCEPT 소켓 옵션이 작동하지 않습니다. 조건부 함수는 여전히 호출되고 WSAAccept 함수는 제대로 작동하지만, 핸드셰이크를 수행할 수 없는 클라이언트를 사용하는 서버 애플리케이션은 제대로 작동하지 않습니다.
 
참고WSAAccept와 같은 차단 Winsock 호출을 실행할 때 Winsock은 호출이 완료되기 전에 네트워크 이벤트를 기다려야 할 수 있습니다. Winsock은 이 상황에서 경고 가능한 대기를 수행합니다. 이 대기는 동일한 스레드에서 예약된 APC(비동기 프로시저 호출)에 의해 중단될 수 있습니다. 동일한 스레드에서 지속적인 차단 Winsock 호출을 중단한 APC 내에서 다른 차단 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 8 이상에서 Windows Phone 스토어 앱에서 지원됩니다.

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

WSAConnect

WSASocket

Winsock 함수

Winsock 참조

받아들일

bind

connect

getsockopt

listen

선택

sockaddr

socket