Condividi tramite


Funzione WSAAccept (winsock2.h)

Il WSAAccept funzione accetta in modo condizionale una connessione in base al valore restituito di una funzione condizione, 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 un sockaddr struttura che riceve l'indirizzo dell'entità di connessione, come noto 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 del sockaddr struttura 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 result g di questa funzione. Se questo parametro è NULL, non viene chiamata alcuna funzione condizione.

[in] dwCallbackData

I dati di callback passati alla funzione 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 addr. 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 l'ha rifiutata attivamente. Questo errore viene restituito se la richiesta di connessione è stata rifiutata forzatamente come indicato nel valore restituito della funzione condizione (CF_REJECT).
WSAECONNRESET
Una connessione esistente è stata chiusa forzatamente dall'host remoto. Questo errore viene restituito di una connessione in ingresso, ma successivamente è stato 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 dal parametro addrlen è troppo piccolo o il addr 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 bloccante di Windows Sockets 1.1 è stata annullata tramite WSACancelBlockingCall.
WSAEINPROGRESS
Un'operazione di blocco è attualmente in esecuzione. Questo errore viene restituito se è in corso una chiamata di Windows Sockets 1.1 bloccante.
WSAEINVAL
È stato fornito un argomento non valido. Questo errore viene restituito se listen non è stato richiamato prima di WSAAccept, il valore restituito della funzione della condizione non è valido o in qualsiasi caso in cui il socket specificato si trova in uno stato non valido.
WSAEMFILE
Troppi socket aperti. Questo errore viene restituito se la coda non è in attesa di immissione per WSAAccept e non sono disponibili descrittori socket.
WSAENETDOWN
Un'operazione socket ha rilevato una rete inattiva. Questo errore viene restituito se il sottosistema di rete non è riuscito.
WSAENOBUFS
Impossibile 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 nel buffer.
WSAENOTSOCK
È stata tentata un'operazione su un elemento che non è un socket. Questo errore viene restituito se il descrittore 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
Impossibile 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 WSAStartupo WSAStartup. Questo errore viene restituito di una chiamata riuscita al WSAStartup funzione dit non si verificano prima di usare questa funzione.
WSATRY_AGAIN
Si tratta in genere di un errore temporaneo durante la risoluzione del nome host e indica 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).

Osservazioni

La funzione WSAAccept estrae la prima connessione nella coda di connessioni in sospeso sul socket e la controlla rispetto alla funzione condizione, purché venga specificata la funzione condizione , ovvero non NULL). Se la funzione della condizione 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 non è possibile prendere immediatamente la decisione, la funzione della 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 eseguire un'azione sulla richiesta di connessione, richiamerà di nuovo WSAAccept e restituirà CF_ACCEPT o CF_REJECT come valore restituito dalla funzione condizione.

Un socket in modalità predefinita (blocco) bloccherà finché 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 non sono presenti connessioni in sospeso nella coda. Dopo 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 di addr è determinato dalla famiglia di indirizzi in cui si sta verificando la comunicazione. Il addrlen è un parametro value-result; deve inizialmente 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 file di intestazione Winsock2.h 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
);

Il ConditionFunc è un segnaposto per la funzione di callback specificata dall'applicazione. La funzione 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, in cui il parametro len è la lunghezza del buffer in byte e il relativo parametro buf è un puntatore al buffer. Il lpCallerData è un parametro di valore che contiene dati utente. Le informazioni contenute in questi parametri vengono inviate insieme alla richiesta di connessione. Se non sono disponibili dati di identificazione o chiamante del chiamante, i parametri corrispondenti verranno 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 di FLOWSPEC per il socket s specificato 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 alcuna qualità del servizio fornita dal chiamante e che non è possibile negoziare. Un puntatoreNULLlpSQOS 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 un uso futuro con i gruppi di socket) fa riferimento alla struttura FLOWSPEC per il gruppo di socket che il chiamante deve creare, una per ogni direzione, seguita da eventuali parametri aggiuntivi specifici del provider. Un valore di NULL per lpGQOS non indica la qualità del servizio del gruppo specificata dal chiamante. La qualità delle informazioni di servizio può essere restituita se si verifica la negoziazione.

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

Il lpCalleeData è un parametro di risultato usato dalla funzione condition per fornire i dati utente all'entità di connessione. Il lpCalleeData->len inizialmente contiene la lunghezza del buffer allocato dal provider di servizi e punta a lpCalleeData->buf. Un valore pari a zero indica che il passaggio dei dati utente al chiamante non è supportato. La funzione condition deve copiare fino a lpCalleeData->len byte di dati in lpCalleeData->bufe quindi aggiornare lpCalleeData->len per indicare il numero effettivo di byte trasferiti. Se nessun dato utente deve essere passato al chiamante, la funzione condizione deve impostare lpCalleeData->len su zero. Il formato di tutti i dati di indirizzo e 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 a questo gruppo, purché vengano soddisfatti tutti i requisiti impostati da questo gruppo.
  • Se g = SG_UNCONSTRAINED_GROUP, creare un gruppo di socket non vincolato e avere come primo membro.
  • Se g = SG_CONSTRAINED_GROUP, creare un gruppo di socket vincolato e avere come primo membro.
  • Se g = zero, non viene eseguita alcuna operazione di gruppo.
Per i gruppi non vincolati, è possibile raggruppare qualsiasi set di socket, purché 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 dello stesso indirizzo nello stesso host. Per i gruppi di socket appena creati, è possibile recuperare il nuovo identificatore di gruppo usando funzione getsockopt con di livello parametro impostato su SOL_SOCKET e il parametro optname impostato su SO_GROUP_ID. Un gruppo di socket e l'ID del gruppo di socket associato rimangono validi fino alla chiusura dell'ultimo socket appartenente a questo gruppo di socket. Gli ID del gruppo di socket sono univoci in tutti i processi per un determinato provider di servizi. Un gruppo di socket e l'identificatore associato rimangono validi fino alla chiusura dell'ultimo socket appartenente a questo gruppo di socket. Gli identificatori del gruppo di 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 di 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. In questo modo un client può passare alcune informazioni di contesto dalla WSAAccept sito di chiamata alla funzione condition. In questo modo la funzione condizione fornisce anche eventuali informazioni aggiuntive necessarie per determinare se accettare o meno la connessione. Un utilizzo tipico consiste nel passare un puntatore (correttamente cast) a una struttura di dati contenente riferimenti a oggetti definiti dall'applicazione a 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 contro gli attacchi SYN in questo modo comporta l'inoperazione dell'opzione socket SO_CONDITIONAL_ACCEPT; la funzione condizionale viene ancora chiamata e la funzione WSAAccept funziona correttamente, ma le applicazioni server che si basano su client che non riescono a eseguire l'handshake non funzioneranno correttamente.
 
Nota Quando si esegue una chiamata Winsock bloccante, ad esempio WSAAccept, Winsock potrebbe dover attendere il completamento di un evento di rete. Winsock esegue un'attesa avvisabile in questa situazione, che può essere interrotta da una chiamata di procedura asincrona pianificata nello stesso thread. L'esecuzione di un'altra chiamata Winsock bloccante 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 tentata 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 di 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.

Fabbisogno

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 Finestre
intestazione winsock2.h
libreria Ws2_32.lib
dll Ws2_32.dll

Vedere anche

WSAAsyncSelect

WSAConnect

WSASocket

Funzioni Winsock

di riferimento winsock

accettare

binding

connettere

getsockopt

ascoltare

selezionare

sockaddr

socket