Fonction AcceptEx (winsock.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.
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.
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)
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);
}
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 | winsock.h (inclure Mswsock.h) |
Bibliothèque | Mswsock.lib |
DLL | Mswsock.dll |