Funzione AcceptEx (mswsock.h)

La funzione AcceptEx accetta una nuova connessione, restituisce l'indirizzo locale e remoto e riceve il primo blocco di dati inviati dall'applicazione client.

Nota Questa funzione è un'estensione specifica di Microsoft per la specifica Windows Sockets.

 

Sintassi

BOOL AcceptEx(
  [in]  SOCKET       sListenSocket,
  [in]  SOCKET       sAcceptSocket,
  [in]  PVOID        lpOutputBuffer,
  [in]  DWORD        dwReceiveDataLength,
  [in]  DWORD        dwLocalAddressLength,
  [in]  DWORD        dwRemoteAddressLength,
  [out] LPDWORD      lpdwBytesReceived,
  [in]  LPOVERLAPPED lpOverlapped
);

Parametri

[in] sListenSocket

Descrittore che identifica un socket già chiamato con la funzione di ascolto . Un'applicazione server attende i tentativi di connessione su questo socket.

[in] sAcceptSocket

Descrittore che identifica un socket su cui accettare una connessione in ingresso. Questo socket non deve essere associato o connesso.

[in] lpOutputBuffer

Puntatore a un buffer che riceve il primo blocco di dati inviati in una nuova connessione, l'indirizzo locale del server e l'indirizzo remoto del client. I dati di ricezione vengono scritti nella prima parte del buffer a partire dall'offset zero, mentre gli indirizzi vengono scritti nella seconda parte del buffer. Questo parametro deve essere specificato.

[in] dwReceiveDataLength

Numero di byte in lpOutputBuffer che verrà usato per i dati di ricezione effettivi all'inizio del buffer. Questa dimensione non deve includere le dimensioni dell'indirizzo locale del server, né l'indirizzo remoto del client; vengono accodati al buffer di output. Se dwReceiveDataLength è zero, l'accettazione della connessione non comporterà un'operazione di ricezione. AccettaEx viene invece completato non appena arriva una connessione, senza attendere alcun dato.

[in] dwLocalAddressLength

Numero di byte riservati alle informazioni sull'indirizzo locale. Questo valore deve essere almeno 16 byte maggiore della lunghezza massima dell'indirizzo per il protocollo di trasporto in uso.

[in] dwRemoteAddressLength

Numero di byte riservati alle informazioni sull'indirizzo remoto. Questo valore deve essere almeno 16 byte maggiore della lunghezza massima dell'indirizzo per il protocollo di trasporto in uso. Impossibile essere zero.

[out] lpdwBytesReceived

Puntatore a un DWORD che riceve il conteggio dei byte ricevuti. Questo parametro viene impostato solo se l'operazione viene completata in modo sincrono. Se restituisce ERROR_IO_PENDING e viene completato in un secondo momento, questa DWORD non viene mai impostata e è necessario ottenere il numero di byte letti dal meccanismo di notifica di completamento.

[in] lpOverlapped

Struttura OVERLAPPED usata per elaborare la richiesta. Questo parametro deve essere specificato; non può essere NULL.

Valore restituito

Se non si verifica alcun errore, la funzione AcceptEx è stata completata correttamente e viene restituito un valore true .

Se la funzione ha esito negativo, AcceptEx restituisce FALSE. La funzione WSAGetLastError può quindi essere chiamata per restituire informazioni di errore estese. Se WSAGetLastError restituisce ERROR_IO_PENDING, l'operazione è stata avviata correttamente ed è ancora in corso. Se l'errore è WSAECONNRESET, è stata indicata una connessione in ingresso, ma successivamente è stata terminata dal peer remoto prima di accettare la chiamata.

Commenti

La funzione AcceptEx combina diverse funzioni socket in una singola transizione API/kernel. La funzione AcceptEx , quando ha esito positivo, esegue tre attività:

  • Viene accettata una nuova connessione.
  • Vengono restituiti sia gli indirizzi locali che remoti per la connessione.
  • Viene ricevuto il primo blocco di dati inviati dal remoto.
Nota Il puntatore della funzione per la funzione AcceptEx deve essere ottenuto in fase di esecuzione eseguendo una chiamata alla funzione WSAIoctlcon il SIO_GET_EXTENSION_FUNCTION_POINTER opcode specificato. Il buffer di input passato alla funzione WSAIoctl deve contenere WSAID_ACCEPTEX, un identificatore univoco globale (GUID) il cui valore identifica la funzione di estensione AcceptEx . In caso di esito positivo, l'output restituito dalla funzione WSAIoctl contiene un puntatore alla funzione AcceptEx . Il GUID WSAID_ACCEPTEX è definito nel file di intestazione Mswsock.h .
 

Un programma può creare una connessione a un socket più rapidamente usando AcceptEx anziché la funzione di accettazione .

Un singolo buffer di output riceve i dati, l'indirizzo del socket locale (il server) e l'indirizzo del socket remoto (client).

L'uso di un singolo buffer migliora le prestazioni. Quando si usa AcceptEx, la funzione GetAcceptExSockaddrs deve essere chiamata per analizzare il buffer nelle tre parti distinte (dati, indirizzo socket locale e indirizzo socket remoto). In Windows XP e versioni successive, una volta completata la funzione AcceptEx e l'opzione SO_UPDATE_ACCEPT_CONTEXT viene impostata sul socket accettato, l'indirizzo locale associato al socket accettato può essere recuperato anche usando la funzione getsockname . Analogamente, l'indirizzo remoto associato al socket accettato può essere recuperato usando la funzione getpeername .

Le dimensioni del buffer per l'indirizzo locale e remoto devono essere di 16 byte superiori alle dimensioni della struttura sockaddr per il protocollo di trasporto in uso perché gli indirizzi vengono scritti in un formato interno. Ad esempio, le dimensioni di un sockaddr_in (la struttura di indirizzi per TCP/IP) è di 16 byte. Pertanto, è necessario specificare una dimensione del buffer di almeno 32 byte per gli indirizzi locali e remoti.

La funzione AcceptEx usa operazioni di I/O sovrapposte, a differenza della funzione di accettazione . Se l'applicazione usa AcceptEx, può usare un numero elevato di client con un numero relativamente ridotto di thread. Come per tutte le funzioni Di Windows sovrapposte, è possibile usare gli eventi di Windows o le porte di completamento come meccanismo di notifica di completamento.

Un'altra differenza chiave tra la funzione AcceptEx e la funzione accept è che AcceptEx richiede che il chiamante abbia già due socket:

  • Oggetto che specifica il socket su cui ascoltare.
  • Oggetto che specifica il socket in cui accettare la connessione.

Il parametro sAcceptSocket deve essere un socket aperto che non è associato né connesso.

Il parametro lpNumberOfBytesTransferred della funzione GetQueuedCompletionStatus o la funzione GetOverlappedResult indica il numero di byte ricevuti nella richiesta.

Al termine dell'operazione, è possibile passare sAcceptSocket , ma solo alle funzioni seguenti:

ReadFile
WriteFile
send
WSASend
Recv
WSARecv
Transmitfile
closesocket
setockopt(solo per SO_UPDATE_ACCEPT_CONTEXT)
Nota Se la funzione TransmitFile viene chiamata con i flag di TF_DISCONNECT e TF_REUSE_SOCKET, il socket specificato è stato restituito a uno stato in cui non è associato né connesso. L'handle socket può quindi essere passato alla funzione AcceptEx nel parametro sAcceptSocket , ma il socket non può essere passato alla funzione ConnectEx .
 

Quando la funzione AcceptEx restituisce, il socket sAcceptSocket è nello stato predefinito per un socket connesso. Il socket sAcceptSocket non eredita le proprietà del socket associato al parametro sListenSocket finché non viene impostato SO_UPDATE_ACCEPT_CONTEXT nel socket. Utilizzare la funzione setockopt per impostare l'opzione SO_UPDATE_ACCEPT_CONTEXT, specificando sAcceptSocket come handle socket e sListenSocket come valore dell'opzione.

Ad esempio:

//Need to #include <mswsock.h> for SO_UPDATE_ACCEPT_CONTEXT

int iResult = 0;

iResult =  setsockopt( sAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, 
    (char *)&sListenSocket, sizeof(sListenSocket) );
   

Se viene fornito un buffer di ricezione, l'operazione sovrapposta non verrà completata finché non viene accettata una connessione e i dati vengono letti. Usare la funzione getsockopt con l'opzione SO_CONNECT_TIME per verificare se è stata accettata una connessione. Se è stata accettata, è possibile determinare quanto tempo è stata stabilita la connessione. Il valore restituito è il numero di secondi che il socket è stato connesso. Se il socket non è connesso, il getsockopt restituisce 0xFFFFFFFF. Le applicazioni che controllano se l'operazione sovrapposta è stata completata, in combinazione con l'opzione SO_CONNECT_TIME, possono determinare che è stata accettata una connessione, ma non sono stati ricevuti dati. La verifica di una connessione in questo modo consente a un'applicazione di determinare se le connessioni stabilite per un po' non hanno ricevuto dati. È consigliabile terminare tali connessioni chiudendo il socket accettato, che impone alla funzione AcceptEx di completare un errore.

Ad esempio:


INT seconds;
INT bytes = sizeof(seconds);
int iResult = 0;

iResult = getsockopt( sAcceptSocket, SOL_SOCKET, SO_CONNECT_TIME,
                      (char *)&seconds, (PINT)&bytes );

if ( iResult != NO_ERROR ) {
    printf( "getsockopt(SO_CONNECT_TIME) failed: %u\n", WSAGetLastError( ) );
    exit(1);
}

Nota Tutti gli I/O avviati da un determinato thread vengono annullati quando il thread viene chiuso. Per i socket sovrapposti, le operazioni asincrone in sospeso possono non riuscire se il thread viene chiuso prima del completamento delle operazioni. Per altre informazioni, vedere ExitThread .
 

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.

Codice di esempio

Nell'esempio seguente viene usata la funzione AcceptEx usando porte di I/O sovrapposte e di completamento.
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include <stdio.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int main()
{
    //----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult = 0;
    BOOL bRetVal = FALSE;

    HANDLE hCompPort;
    HANDLE hCompPort2;
    
    LPFN_ACCEPTEX lpfnAcceptEx = NULL;
    GUID GuidAcceptEx = WSAID_ACCEPTEX;
    WSAOVERLAPPED olOverlap;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET AcceptSocket = INVALID_SOCKET;
    sockaddr_in service;
    char lpOutputBuf[1024];
    int outBufLen = 1024;
    DWORD dwBytes;

    hostent *thisHost;
    char *ip;
    u_short port;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"Error at WSAStartup\n");
        return 1;
    }    

    // Create a handle for the completion port
    hCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (u_long) 0, 0);
    if (hCompPort == NULL) {
        wprintf(L"CreateIoCompletionPort failed with error: %u\n",
            GetLastError() );
        WSACleanup();
        return 1;
    }
            
    // Create a listening socket
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"Create of ListenSocket socket failed with error: %u\n",
            WSAGetLastError() );
        WSACleanup();
        return 1;
    }

    // Associate the listening socket with the completion port
    CreateIoCompletionPort((HANDLE) ListenSocket, hCompPort, (u_long) 0, 0);

    //----------------------------------------
    // Bind the listening socket to the local IP address
    // and port 27015
    port = 27015;
    thisHost = gethostbyname("");
    ip = inet_ntoa(*(struct in_addr *) *thisHost->h_addr_list);

    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr(ip);
    service.sin_port = htons(port);

    if (bind(ListenSocket, (SOCKADDR *) & service, sizeof (service)) == SOCKET_ERROR) {
        wprintf(L"bind failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    //----------------------------------------
    // Start listening on the listening socket
    iResult = listen(ListenSocket, 100);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"listen failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    wprintf(L"Listening on address: %s:%d\n", ip, port);

    // Load the AcceptEx function into memory using WSAIoctl.
    // The WSAIoctl function is an extension of the ioctlsocket()
    // function that can use overlapped I/O. The function's 3rd
    // through 6th parameters are input and output buffers where
    // we pass the pointer to our AcceptEx function. This is used
    // so that we can call the AcceptEx function directly, rather
    // than refer to the Mswsock.lib library.
    iResult = WSAIoctl(ListenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER,
             &GuidAcceptEx, sizeof (GuidAcceptEx), 
             &lpfnAcceptEx, sizeof (lpfnAcceptEx), 
             &dwBytes, NULL, NULL);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"WSAIoctl failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Create an accepting socket
    AcceptSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (AcceptSocket == INVALID_SOCKET) {
        wprintf(L"Create accept socket failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Empty our overlapped structure and accept connections.
    memset(&olOverlap, 0, sizeof (olOverlap));

    bRetVal = lpfnAcceptEx(ListenSocket, AcceptSocket, lpOutputBuf,
                 outBufLen - ((sizeof (sockaddr_in) + 16) * 2),
                 sizeof (sockaddr_in) + 16, sizeof (sockaddr_in) + 16, 
                 &dwBytes, &olOverlap);
    if (bRetVal == FALSE) {
        wprintf(L"AcceptEx failed with error: %u\n", WSAGetLastError());
        closesocket(AcceptSocket);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Associate the accept socket with the completion port
    hCompPort2 = CreateIoCompletionPort((HANDLE) AcceptSocket, hCompPort, (u_long) 0, 0); 
    // hCompPort2 should be hCompPort if this succeeds
    if (hCompPort2 == NULL) {
        wprintf(L"CreateIoCompletionPort associate failed with error: %u\n",
            GetLastError() );
        closesocket(AcceptSocket);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    
    // Continue on to use send, recv, TransmitFile(), etc.,.
    //...

    return 0;
}


Note per QoS

La funzione TransmitFile consente l'impostazione di due flag, TF_DISCONNECT o TF_REUSE_SOCKET, che restituiscono il socket a uno stato "disconnesso, riutilizzabile" dopo la trasmissione del file. Questi flag non devono essere usati in un socket in cui è stata richiesta la qualità del servizio, poiché il provider di servizi può eliminare immediatamente qualsiasi qualità del servizio associato al socket prima del completamento del trasferimento del file. L'approccio migliore per un socket abilitato per QoS consiste nel chiamare semplicemente la funzione closesocket al termine del trasferimento dei file anziché basarsi su questi flag.

Note per ATM

Si verificano problemi importanti associati all'installazione della connessione quando si usa la modalità di trasferimento asincrona (ATM) con Windows Sockets 2. Vedere la sezione Osservazioni nella documentazione della funzione accept per informazioni importanti sulla configurazione della connessione ATM.

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 mswsock.h (include Mswsock.h)
Libreria Mswsock.lib
DLL Mswsock.dll

Vedi anche

GetAcceptExSockaddrs

GetOverlappedResult

GetQueuedCompletionStatus

SOVRAPPOSTA

Transmitfile

Funzioni Winsock

Informazioni di riferimento su Winsock

Accettare

closesocket

getsockopt

listen

sockaddr