Fonction AcceptEx (mswsock.h)

La fonction AcceptEx accepte une nouvelle connexion, retourne l’adresse locale et distante et reçoit le premier bloc de données envoyé par l’application cliente.

Note Cette fonction est une extension spécifique à Microsoft de la spécification des sockets Windows.

 

Syntaxe

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
);

Paramètres

[in] sListenSocket

Descripteur identifiant un socket qui a déjà été appelé avec la fonction d’écoute . Une application serveur attend les tentatives de connexion sur ce socket.

[in] sAcceptSocket

Descripteur identifiant un socket sur lequel accepter une connexion entrante. Ce socket ne doit pas être lié ou connecté.

[in] lpOutputBuffer

Pointeur vers une mémoire tampon qui reçoit le premier bloc de données envoyé sur une nouvelle connexion, l’adresse locale du serveur et l’adresse distante du client. Les données de réception sont écrites dans la première partie de la mémoire tampon à partir du décalage zéro, tandis que les adresses sont écrites dans la dernière partie de la mémoire tampon. Ce paramètre doit être spécifié.

[in] dwReceiveDataLength

Nombre d’octets dans lpOutputBuffer qui seront utilisés pour les données de réception réelles au début de la mémoire tampon. Cette taille ne doit pas inclure la taille de l’adresse locale du serveur, ni l’adresse distante du client ; ils sont ajoutés à la mémoire tampon de sortie. Si dwReceiveDataLength est égal à zéro, l’acceptation de la connexion n’entraîne pas d’opération de réception. Au lieu de cela, AcceptEx se termine dès qu’une connexion arrive, sans attendre de données.

[in] dwLocalAddressLength

Nombre d’octets réservés aux informations d’adresse locale. Cette valeur doit être supérieure d’au moins 16 octets à la longueur d’adresse maximale du protocole de transport utilisé.

[in] dwRemoteAddressLength

Nombre d’octets réservés aux informations d’adresse distante. Cette valeur doit être supérieure d’au moins 16 octets à la longueur d’adresse maximale du protocole de transport utilisé. Impossible d’être égal à zéro.

[out] lpdwBytesReceived

Pointeur vers un DWORD qui reçoit le nombre d’octets reçus. Ce paramètre est défini uniquement si l’opération se termine de manière synchrone. S’il retourne ERROR_IO_PENDING et est terminé ultérieurement, ce DWORD n’est jamais défini et vous devez obtenir le nombre d’octets lus à partir du mécanisme de notification d’achèvement.

[in] lpOverlapped

Structure CHEVAUCHÉE utilisée pour traiter la demande. Ce paramètre doit être spécifié ; il ne peut pas être NULL.

Valeur retournée

Si aucune erreur ne se produit, la fonction AcceptEx s’est terminée correctement et la valeur TRUE est retournée.

Si la fonction échoue, AcceptEx retourne FALSE. La fonction WSAGetLastError peut ensuite être appelée pour retourner des informations d’erreur étendues. Si WSAGetLastError retourne ERROR_IO_PENDING, l’opération a été lancée avec succès et est toujours en cours. Si l’erreur est WSAECONNRESET, une connexion entrante a été indiquée, mais a ensuite été arrêtée par l’homologue distant avant d’accepter l’appel.

Remarques

La fonction AcceptEx combine plusieurs fonctions de socket en une seule transition API/noyau. Lorsqu’elle réussit, la fonction AcceptEx effectue trois tâches :

  • Une nouvelle connexion est acceptée.
  • Les adresses locales et distantes de la connexion sont retournées.
  • Le premier bloc de données envoyé par le distant est reçu.
Note Le pointeur de fonction pour la fonction AcceptEx doit être obtenu au moment de l’exécution en appelant la fonction WSAIoctl avec le SIO_GET_EXTENSION_FUNCTION_POINTER opcode spécifié. La mémoire tampon d’entrée passée à la fonction WSAIoctl doit contenir WSAID_ACCEPTEX, un identificateur global unique (GUID) dont la valeur identifie la fonction d’extension AcceptEx . En cas de réussite, la sortie retournée par la fonction WSAIoctl contient un pointeur vers la fonction AcceptEx . Le GUID WSAID_ACCEPTEX est défini dans le fichier d’en-tête Mswsock.h .
 

Un programme peut créer une connexion à un socket plus rapidement à l’aide d’AcceptEx au lieu de la fonction d’acceptation .

Une mémoire tampon de sortie unique reçoit les données, l’adresse du socket local (le serveur) et l’adresse du socket distant (le client).

L’utilisation d’une mémoire tampon unique améliore les performances. Lorsque vous utilisez AcceptEx, la fonction GetAcceptExSockaddrs doit être appelée pour analyser la mémoire tampon dans ses trois parties distinctes (données, adresse de socket local et adresse de socket distante). Sur Windows XP et versions ultérieures, une fois la fonction AcceptEx terminée et l’option SO_UPDATE_ACCEPT_CONTEXT définie sur le socket accepté, l’adresse locale associée au socket accepté peut également être récupérée à l’aide de la fonction getsockname . De même, l’adresse distante associée au socket accepté peut être récupérée à l’aide de la fonction getpeername .

La taille de la mémoire tampon pour l’adresse locale et distante doit être supérieure de 16 octets à la taille de la structure sockaddr pour le protocole de transport utilisé, car les adresses sont écrites dans un format interne. Par exemple, la taille d’un sockaddr_in (structure d’adresse pour TCP/IP) est de 16 octets. Par conséquent, une taille de mémoire tampon d’au moins 32 octets doit être spécifiée pour les adresses locales et distantes.

La fonction AcceptEx utilise des E/S qui se chevauchent, contrairement à la fonction accept . Si votre application utilise AcceptEx, elle peut traiter un grand nombre de clients avec un nombre relativement faible de threads. Comme pour toutes les fonctions Windows qui se chevauchent, les événements Windows ou les ports d’achèvement peuvent être utilisés comme mécanisme de notification d’achèvement.

Une autre différence clé entre la fonction AcceptEx et la fonction accept est que AcceptEx exige que l’appelant dispose déjà de deux sockets :

  • Un qui spécifie le socket sur lequel écouter.
  • Un qui spécifie le socket sur lequel accepter la connexion.

Le paramètre sAcceptSocket doit être un socket ouvert qui n’est ni lié ni connecté.

Le paramètre lpNumberOfBytesTransferred de la fonction GetQueuedCompletionStatus ou de la fonction GetOverlappedResult indique le nombre d’octets reçus dans la requête.

Une fois cette opération terminée, sAcceptSocket peut être passé, mais aux fonctions suivantes uniquement :

ReadFile
WriteFile
envoyer
WSASend
Recv
WSARecv
TransmitFile
closesocket
setsockopt(uniquement pour SO_UPDATE_ACCEPT_CONTEXT)
Note Si la fonction TransmitFile est appelée avec les indicateurs TF_DISCONNECT et TF_REUSE_SOCKET, le socket spécifié a été retourné à un état dans lequel il n’est ni lié ni connecté. Le handle de socket peut ensuite être passé à la fonction AcceptEx dans le paramètre sAcceptSocket , mais le socket ne peut pas être passé à la fonction ConnectEx .
 

Lorsque la fonction AcceptEx retourne, le socket sAcceptSocket est à l’état par défaut pour un socket connecté. Le socket sAcceptSocket n’hérite pas des propriétés du socket associé au paramètre sListenSocket tant que SO_UPDATE_ACCEPT_CONTEXT n’est pas défini sur le socket. Utilisez la fonction setsockopt pour définir l’option SO_UPDATE_ACCEPT_CONTEXT, en spécifiant sAcceptSocket comme handle de socket et sListenSocket comme valeur d’option.

Par exemple :

//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) );
   

Si une mémoire tampon de réception est fournie, l’opération qui se chevauche ne se termine pas tant qu’une connexion n’est pas acceptée et que les données ne sont pas lues. Utilisez la fonction getsockopt avec l’option SO_CONNECT_TIME pour case activée si une connexion a été acceptée. S’il a été accepté, vous pouvez déterminer la durée pendant laquelle la connexion a été établie. La valeur de retour correspond au nombre de secondes pendant lesquelles le socket a été connecté. Si le socket n’est pas connecté, le getsockopt retourne 0xFFFFFFFF. Les applications qui case activée si l’opération qui se chevauche est terminée, en combinaison avec l’option SO_CONNECT_TIME, peuvent déterminer qu’une connexion a été acceptée, mais qu’aucune donnée n’a été reçue. L’examen d’une connexion de cette manière permet à une application de déterminer si les connexions établies depuis un certain temps n’ont reçu aucune donnée. Il est recommandé d’arrêter ces connexions en fermant le socket accepté, ce qui force l’appel de fonction AcceptEx à se terminer avec une erreur.

Par exemple :


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);
}

Note Toutes les E/S initiées par un thread donné sont annulées à la sortie de ce thread. Pour les sockets qui se chevauchent, les opérations asynchrones en attente peuvent échouer si le thread est fermé avant la fin des opérations. Pour plus d’informations, consultez ExitThread .
 

Windows Phone 8 : cette fonction est prise en charge pour les applications du Store Windows Phone Windows Phone 8 et versions ultérieures.

Windows 8.1 et Windows Server 2012 R2 : cette fonction est prise en charge pour les applications du Windows Store sur Windows 8.1, Windows Server 2012 R2 et versions ultérieures.

Exemple de code

L’exemple suivant utilise la fonction AcceptEx à l’aide de ports d’E/S et d’achèvement qui se chevauchent.
#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;
}


Remarques relatives à QoS

La fonction TransmitFile permet de définir deux indicateurs, TF_DISCONNECT ou TF_REUSE_SOCKET, qui retournent le socket à un état « déconnecté, réutilisable » après la transmission du fichier. Ces indicateurs ne doivent pas être utilisés sur un socket où la qualité de service a été demandée, car le fournisseur de services peut supprimer immédiatement toute qualité de service associée au socket avant la fin du transfert de fichiers. La meilleure approche pour un socket prenant en charge QoS consiste simplement à appeler la fonction closesocket une fois le transfert de fichier terminé, plutôt que de s’appuyer sur ces indicateurs.

Remarques pour ATM

Il existe d’importants problèmes associés à la configuration de la connexion lors de l’utilisation du mode de transfert asynchrone (ATM) avec Windows Sockets 2. Consultez la section Remarques de la documentation accepter la fonction pour obtenir des informations importantes sur la configuration de la connexion ATM.

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows 8.1, Windows Vista [applications de bureau | Applications UWP]
Serveur minimal pris en charge Windows Server 2003 [applications de bureau | applications UWP]
Plateforme cible Windows
En-tête mswsock.h (inclure Mswsock.h)
Bibliothèque Mswsock.lib
DLL Mswsock.dll

Voir aussi

GetAcceptExSockaddrs

GetOverlappedResult

GetQueuedCompletionStatus

OVERLAPPED

TransmitFile

Fonctions Winsock

Informations de référence sur Winsock

Accepter

closesocket

getsockopt

listen

sockaddr