Funzione WSAAccept (winsock2.h)

La funzione WSAAccept accetta in modo condizionale una connessione in base al valore restituito di una funzione condition, fornisce la qualità delle specifiche del flusso di servizio e consente il trasferimento dei dati di connessione.

Sintassi

SOCKET WSAAPI WSAAccept(
  [in]      SOCKET          s,
  [out]     sockaddr        *addr,
  [in, out] LPINT           addrlen,
  [in]      LPCONDITIONPROC lpfnCondition,
  [in]      DWORD_PTR       dwCallbackData
);

Parametri

[in] s

Descrittore che identifica un socket in ascolto delle connessioni dopo una chiamata alla funzione listen .

[out] addr

Puntatore facoltativo a una struttura sockaddr che riceve l'indirizzo dell'entità di connessione, nota al livello di comunicazione. Il formato esatto del parametro addr è determinato dalla famiglia di indirizzi stabilita al momento della creazione del socket.

[in, out] addrlen

Puntatore facoltativo a un numero intero contenente la lunghezza della struttura sockaddr a cui punta il parametro addr , in byte.

[in] lpfnCondition

Indirizzo di una funzione di condizione facoltativa specificata dall'applicazione che effettuerà una decisione di accettazione/rifiuto in base alle informazioni del chiamante passate come parametri e, facoltativamente, creare o unire un gruppo di socket assegnando un valore appropriato al parametro di risultato g di questa funzione. Se questo parametro è NULL, non viene chiamata alcuna funzione condition.

[in] dwCallbackData

I dati di callback passati alla funzione di condizione specificata dall'applicazione come valore del parametro dwCallbackData passato alla funzione condition. Questo parametro è applicabile solo se il parametro lpfnCondition non è NULL. Questo parametro non viene interpretato da Windows Sockets.

Valore restituito

Se non si verifica alcun errore, WSAAccept restituisce un valore di tipo SOCKET che è un descrittore per il socket accettato. In caso contrario, viene restituito un valore di INVALID_SOCKET e un codice di errore specifico può essere recuperato chiamando WSAGetLastError.

L'intero a cui fa riferimento addrlen inizialmente contiene la quantità di spazio a cui punta il componente aggiuntivo. In caso di restituzione, conterrà la lunghezza effettiva in byte dell'indirizzo restituito.

Codice di errore Significato
WSAEACCES
È stato effettuato un tentativo di accesso a un socket in modo non consentito dalle autorizzazioni di accesso. Questo errore viene restituito se la richiesta di connessione offerta è scaduta o ritirata.
WSAECONNREFUSED
Non è stato possibile stabilire alcuna connessione perché il computer di destinazione lo ha rifiutato attivamente. Questo errore viene restituito se la richiesta di connessione è stata rifiutata forzatamente come indicato nel valore restituito della funzione condizione (CF_REJECT).
WSAECONNRESET
Connessione in corso interrotta forzatamente dall'host remoto. Questo errore viene restituito di una connessione in ingresso, ma è stato successivamente terminato dal peer remoto prima di accettare la chiamata.
WSAEFAULT
Il sistema ha rilevato un indirizzo puntatore non valido nel tentativo di usare un argomento puntatore in una chiamata. Questo errore viene restituito del parametro addrlen troppo piccolo o il componente aggiuntivo o lpfnCondition non fa parte dello spazio indirizzi utente.
WSAEINTR
Un'operazione di blocco è stata interrotta da una chiamata a WSACancelBlockingCall. Questo errore viene restituito se una chiamata di Windows Sockets 1.1 bloccante è stata annullata tramite WSACancelBlockingCall.
WSAEINPROGRESS
È in corso un'operazione di blocco. Questo errore viene restituito se è in corso una chiamata di Windows Sockets 1.1 bloccante.
WSAEINVAL
Argomento fornito non valido. Questo errore viene restituito se il listen non è stato richiamato prima di WSAAccept, il valore restituito della funzione di condizione non è valido oppure se il socket specificato è in uno stato non valido.
WSAEMFILE
Troppi socket aperti. Questo errore viene restituito se la coda non viene annullata al momento dell'immissione in WSAAccept e non sono disponibili descrittori socket.
WSAENETDOWN
Rete inattiva rilevata durante l'operazione del socket. Questo errore viene restituito se il sottosistema di rete non è riuscito.
WSAENOBUFS
Non è stato possibile eseguire un'operazione su un socket perché il sistema non disponeva di spazio sufficiente nel buffer o perché una coda era piena. Questo errore viene restituito se non è disponibile spazio buffer.
WSAENOTSOCK
È stata tentata un'operazione su un elemento che non è un socket. Questo errore viene restituito se il descrittore del socket passato nel parametro s non è un socket.
WSAEOPNOTSUPP
La famiglia di protocolli non è stata configurata nel sistema o non esiste alcuna implementazione. Questo errore viene restituito se il socket a cui si fa riferimento non è un tipo che supporta il servizio orientato alla connessione.
WSAEWOULDBLOCK
Non è stato possibile completare immediatamente un'operazione socket non bloccabile. Questo errore viene restituito se il socket è contrassegnato come non bloccante e non sono presenti connessioni da accettare.
WSANOTINITIALISED
L'applicazione non ha chiamato WSAStartup o WSAStartup non è riuscita. Questo errore viene restituito quando una chiamata alla funzione WSAStartup non viene eseguita prima di usare questa funzione.
WSATRY_AGAIN
Generalmente, questo è un errore temporaneo che si verifica durante la risoluzione dei nomi host e significa che il server locale non ha ricevuto una risposta da un server autorevole. Questo errore viene restituito se l'accettazione della richiesta di connessione è stata posticipata come indicato nel valore restituito della funzione condizione (CF_DEFER).

Commenti

La funzione WSAAccept estrae la prima connessione nella coda di connessioni in sospeso sul socket s e la controlla rispetto alla funzione condizione, purché venga specificata la funzione condizione , ovvero non NULL. Se la funzione condition restituisce CF_ACCEPT, WSAAccept crea un nuovo socket. Il socket appena creato ha le stesse proprietà del socket, inclusi gli eventi asincroni registrati con WSAAsyncSelect o con WSAEventSelect. Se la funzione condition restituisce CF_REJECT, WSAAccept rifiuta la richiesta di connessione. La funzione condition viene eseguita nello stesso thread di questa funzione e deve restituire il prima possibile. Se la decisione non può essere presa immediatamente, la funzione condizione deve restituire CF_DEFER per indicare che non è stata presa alcuna decisione e non deve essere eseguita alcuna azione su questa richiesta di connessione da parte del provider di servizi. Quando l'applicazione è pronta per intervenire sulla richiesta di connessione, richiama nuovamente WSAAccept e restituisce CF_ACCEPT o CF_REJECT come valore restituito dalla funzione condition.

Un socket in modalità predefinita (blocco) verrà bloccato fino a quando non è presente una connessione quando un'applicazione chiama WSAAccept e nessuna connessione è in sospeso nella coda.

Un socket in modalità non bloccante (blocco) ha esito negativo con l'errore WSAEWOULDBLOCK quando un'applicazione chiama WSAAccept e nessuna connessione è in sospeso nella coda. Dopo che WSAAccept ha esito positivo e restituisce un nuovo handle socket, il socket accettato non può essere usato per accettare altre connessioni. Il socket originale rimane aperto e rimane in ascolto delle nuove richieste di connessione.

Il parametro addr è un parametro di risultato compilato con l'indirizzo dell'entità di connessione, noto al livello di comunicazione. Il formato esatto del parametro addr è determinato dalla famiglia di indirizzi in cui si verifica la comunicazione. Addrlen è un parametro value-result; inizialmente deve contenere la quantità di spazio a cui punta addr. In caso di restituzione, conterrà la lunghezza effettiva (in byte) dell'indirizzo restituito. Questa chiamata viene usata con tipi socket orientati alla connessione, ad esempio SOCK_STREAM. Se addr e/o addrlen sono uguali a NULL, non vengono restituite informazioni sull'indirizzo remoto del socket accettato. In caso contrario, questi due parametri verranno compilati se la connessione viene accettata correttamente.

Un prototipo della funzione condizione viene definito nel Winsock2.h file di intestazione come LPCONDITIONPROC, come indicato di seguito.

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 è un segnaposto per la funzione di callback specificata dall'applicazione. La funzione di condizione effettiva deve risiedere in una DLL o in un modulo dell'applicazione. Viene esportata nel file di definizione del modulo.

Il parametro lpCallerId punta a una struttura WSABUF che contiene l'indirizzo dell'entità di connessione, dove il relativo parametro len è la lunghezza del buffer in byte e il relativo parametro buf è un puntatore al buffer. lpCallerData è un parametro di valore che contiene i dati utente. Le informazioni contenute in questi parametri vengono inviate insieme alla richiesta di connessione. Se non sono disponibili dati di identificazione del chiamante o chiamante, i parametri corrispondenti saranno NULL. Molti protocolli di rete non supportano i dati del chiamante in fase di connessione. La maggior parte dei protocolli di rete convenzionali può essere prevista per supportare le informazioni sull'identificatore del chiamante in fase di richiesta di connessione. La parte buf del WSABUF a cui punta lpCallerId punta a un sockaddr. La struttura sockaddr viene interpretata in base alla famiglia di indirizzi (in genere eseguendo il cast del sockaddr a un tipo specifico della famiglia di indirizzi).

Il parametro lpSQOS fa riferimento alle strutture FLOWSPECper i socket specificati dal chiamante, uno per ogni direzione, seguito da eventuali parametri aggiuntivi specifici del provider. I valori di specifica del flusso di invio o ricezione verranno ignorati in base alle esigenze di qualsiasi socket unidirezionale. Un valore NULL indica che non esiste una qualità del servizio fornita dal chiamante e che non è possibile negoziare. Un puntatore non NULLlpSQOS indica che si verifica una qualità della negoziazione del servizio o che il provider è pronto ad accettare la qualità della richiesta di servizio senza negoziazione.

Il parametro lpGQOS è riservato e deve essere NULL. (riservato per l'uso futuro con i gruppi di socket) fa riferimento alla struttura FLOWPEC per il gruppo di socket che il chiamante deve creare, uno per ogni direzione, seguito da eventuali parametri specifici del provider aggiuntivi. Un valore NULL per lpGQOS non indica la qualità del gruppo specificata dal chiamante del servizio. La qualità delle informazioni sui servizi può essere restituita se si verifica la negoziazione.

LpCalleeId è un parametro che contiene l'indirizzo locale dell'entità connessa. La parte buf del WSABUF puntata da lpCalleeId punta a una struttura sockaddr . La struttura sockaddr viene interpretata in base alla famiglia di indirizzi (in genere eseguendo il cast del sockaddr a un tipo specifico della famiglia di indirizzi, ad esempio struct sockaddr_in).

LpCalleeData è un parametro di risultato usato dalla funzione condizione per fornire i dati utente all'entità di connessione. LpCalleeData-len contiene inizialmente la lunghezza del buffer allocata dal provider di servizi e punta a lpCalleeData-buf>>. Un valore pari a zero significa che il passaggio dei dati utente al chiamante non è supportato. La funzione condizione deve copiare fino a lpCalleeData-len byte di dati in lpCalleeData-buf>>e quindi aggiornare lpCalleeData-len> per indicare il numero effettivo di byte trasferiti. Se non vengono passati dati utente al chiamante, la funzione condizione deve impostare lpCalleeData-len> su zero. Il formato di tutti gli indirizzi e i dati utente è specifico della famiglia di indirizzi a cui appartiene il socket.

Il parametro g viene assegnato all'interno della funzione condition per indicare una delle azioni seguenti:

  • Se g è un identificatore del gruppo di socket esistente, aggiungere s a questo gruppo, purché vengano soddisfatti tutti i requisiti impostati da questo gruppo.
  • Se g = SG_UNCONSTRAINED_GROUP, creare un gruppo socket non vincolato e avere come primo membro.
  • Se g = SG_CONSTRAINED_GROUP, creare un gruppo socket vincolato e avere come primo membro.
  • Se g = zero, non viene eseguita alcuna operazione di gruppo.
Per i gruppi non vincolati, qualsiasi set di socket può essere raggruppato a condizione che siano supportati da un singolo provider di servizi. Un gruppo di socket vincolato può essere costituito solo da socket orientati alla connessione e richiede che le connessioni su tutti i socket raggruppati siano allo stesso indirizzo nello stesso host. Per i gruppi di socket appena creati, il nuovo identificatore di gruppo può essere recuperato usando la funzione getsockopt con parametro di livello impostato su SOL_SOCKET e il parametro optname impostato su SO_GROUP_ID. Un gruppo socket e l'ID del gruppo socket associato rimangono validi fino all'ultimo socket appartenente a questo gruppo di socket. Gli ID del gruppo socket sono univoci in tutti i processi per un determinato provider di servizi. Un gruppo di socket e il relativo identificatore associato rimangono validi fino all'ultimo socket appartenente a questo gruppo di socket. Gli identificatori di gruppo socket sono univoci in tutti i processi per un determinato provider di servizi. Per altre informazioni sui gruppi di socket, vedere le osservazioni per le funzioni WSASocket .

Il valore del parametro dwCallbackData passato alla funzione condition è il valore passato come parametro dwCallbackData nella chiamata WSAAccept originale. Questo valore viene interpretato solo dal client Windows Socket versione 2. Ciò consente a un client di passare alcune informazioni di contesto dal sito di chiamata WSAAccept tramite la funzione condizione. In questo modo la funzione condizione fornisce anche informazioni aggiuntive necessarie per determinare se accettare la connessione o meno. Un utilizzo tipico consiste nel passare un puntatore (in modo adeguato) a una struttura di dati contenente riferimenti agli oggetti definiti dall'applicazione con cui è associato questo socket.

Nota Per proteggere l'uso della funzione WSAAccept dagli attacchi SYN, le applicazioni devono eseguire handshake TCP completi (SYN-SYNACK-ACK) prima di segnalare la richiesta di connessione. La protezione dagli attacchi SYN in questo modo comporta l'opzione socket SO_CONDITIONAL_ACCEPT che diventa inoperativa; la funzione condizionale viene ancora chiamata e la funzione WSAAccept funziona correttamente, ma le applicazioni server che si basano sui client che non possono eseguire l'handshake non funzioneranno correttamente.
 
Nota Quando si emette una chiamata Winsock bloccante, ad esempio WSAAccept, Winsock potrebbe dover attendere un evento di rete prima che la chiamata possa essere completata. Winsock esegue un'attesa avvisabile in questa situazione, che può essere interrotta da una chiamata di routine asincrona pianificata nello stesso thread. L'emissione di un'altra chiamata winsock bloccata all'interno di un APC che ha interrotto una chiamata winsock in corso sullo stesso thread comporterà un comportamento non definito e non deve mai essere tentato dai client Winsock.
 

Codice di esempio

Nell'esempio seguente viene illustrato l'uso della funzione 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: questa funzione è supportata per le app Windows Phone Store in Windows Phone 8 e versioni successive.

Windows 8.1 e Windows Server 2012 R2: questa funzione è supportata per le app di Windows Store in Windows 8.1, Windows Server 2012 R2 e versioni successive.

Requisiti

Requisito Valore
Client minimo supportato Windows 8.1, Windows Vista [app desktop | App UWP]
Server minimo supportato Windows Server 2003 [app desktop | App UWP]
Piattaforma di destinazione Windows
Intestazione winsock2.h
Libreria Ws2_32.lib
DLL Ws2_32.dll

Vedi anche

WSAAsyncSelect

WSAConnect

WSASocket

Funzioni Winsock

Informazioni di riferimento su Winsock

Accettare

bind

connect

getsockopt

listen

select

sockaddr

socket