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