Função AcceptEx (winsock.h)
A função AcceptEx aceita uma nova conexão, retorna o endereço local e remoto e recebe o primeiro bloco de dados enviado pelo aplicativo cliente.
Sintaxe
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
);
Parâmetros
[in] sListenSocket
Um descritor que identifica um soquete que já foi chamado com a função de escuta . Um aplicativo de servidor aguarda as tentativas de conexão nesse soquete.
[in] sAcceptSocket
Um descritor que identifica um soquete no qual aceitar uma conexão de entrada. Esse soquete não deve estar associado ou conectado.
[in] lpOutputBuffer
Um ponteiro para um buffer que recebe o primeiro bloco de dados enviado em uma nova conexão, o endereço local do servidor e o endereço remoto do cliente. Os dados de recebimento são gravados na primeira parte do buffer começando no deslocamento zero, enquanto os endereços são gravados na última parte do buffer. Esse parâmetro precisa ser especificado.
[in] dwReceiveDataLength
O número de bytes em lpOutputBuffer que serão usados para dados de recebimento reais no início do buffer. Esse tamanho não deve incluir o tamanho do endereço local do servidor, nem o endereço remoto do cliente; eles são acrescentados ao buffer de saída. Se dwReceiveDataLength for zero, aceitar a conexão não resultará em uma operação de recebimento. Em vez disso, AcceptEx é concluído assim que uma conexão chega, sem aguardar nenhum dado.
[in] dwLocalAddressLength
O número de bytes reservados para as informações de endereço local. Esse valor deve ser pelo menos 16 bytes a mais do que o comprimento máximo do endereço para o protocolo de transporte em uso.
[in] dwRemoteAddressLength
O número de bytes reservados para as informações de endereço remoto. Esse valor deve ser pelo menos 16 bytes a mais do que o comprimento máximo do endereço para o protocolo de transporte em uso. Não pode ser zero.
[out] lpdwBytesReceived
Um ponteiro para um DWORD que recebe a contagem de bytes recebidos. Esse parâmetro será definido somente se a operação for concluída de forma síncrona. Se ele retornar ERROR_IO_PENDING e for concluído posteriormente, esse DWORD nunca será definido e você deverá obter o número de bytes lidos do mecanismo de notificação de conclusão.
[in] lpOverlapped
Uma estrutura OVERLAPPED usada para processar a solicitação. Esse parâmetro deve ser especificado; não pode ser NULL.
Retornar valor
Se nenhum erro ocorrer, a função AcceptEx será concluída com êxito e um valor true será retornado.
Se a função falhar, AcceptEx retornará FALSE. A função WSAGetLastError pode ser chamada para retornar informações de erro estendidas. Se WSAGetLastError retornar ERROR_IO_PENDING, a operação foi iniciada com êxito e ainda está em andamento. Se o erro for WSAECONNRESET, uma conexão de entrada foi indicada, mas posteriormente foi encerrada pelo par remoto antes de aceitar a chamada.
Comentários
A função AcceptEx combina várias funções de soquete em uma única transição de API/kernel. A função AcceptEx , quando bem-sucedida, executa três tarefas:
- Uma nova conexão é aceita.
- Os endereços locais e remotos da conexão são retornados.
- O primeiro bloco de dados enviado pelo remoto é recebido.
Um programa pode fazer uma conexão com um soquete mais rapidamente usando AcceptEx em vez da função accept .
Um único buffer de saída recebe os dados, o endereço do soquete local (o servidor) e o endereço do soquete remoto (o cliente).
O uso de um único buffer melhora o desempenho. Ao usar AcceptEx, a função GetAcceptExSockaddrs deve ser chamada para analisar o buffer em suas três partes distintas (dados, endereço de soquete local e endereço de soquete remoto). No Windows XP e posterior, depois que a função AcceptEx for concluída e a opção SO_UPDATE_ACCEPT_CONTEXT for definida no soquete aceito, o endereço local associado ao soquete aceito também poderá ser recuperado usando a função getsockname . Da mesma forma, o endereço remoto associado ao soquete aceito pode ser recuperado usando a função getpeername .
O tamanho do buffer para o endereço local e remoto deve ser 16 bytes a mais do que o tamanho da estrutura sockaddr para o protocolo de transporte em uso porque os endereços são gravados em um formato interno. Por exemplo, o tamanho de um sockaddr_in (a estrutura de endereços para TCP/IP) é de 16 bytes. Portanto, um tamanho de buffer de pelo menos 32 bytes deve ser especificado para os endereços locais e remotos.
A função AcceptEx usa E/S sobreposta, ao contrário da função accept . Se seu aplicativo usa AcceptEx, ele pode atender a um grande número de clientes com um número relativamente pequeno de threads. Assim como acontece com todas as funções sobrepostas do Windows, os eventos do Windows ou as portas de conclusão podem ser usados como um mecanismo de notificação de conclusão.
Outra diferença importante entre a função AcceptEx e a função accept é que AcceptEx exige que o chamador já tenha dois soquetes:
- Um que especifica o soquete no qual escutar.
- Um que especifica o soquete no qual aceitar a conexão.
O parâmetro sAcceptSocket deve ser um soquete aberto que não esteja associado nem conectado.
O parâmetro lpNumberOfBytesTransferred da função GetQueuedCompletionStatus ou da função GetOverlappedResult indica o número de bytes recebidos na solicitação.
Quando essa operação é concluída com êxito, sAcceptSocket pode ser passado, mas apenas para as seguintes funções:
- ReadFile
- WriteFile
- send
- WSASend
- Recv
- WSARecv
- Transmitfile
- Closesocket
- setsockopt(only for SO_UPDATE_ACCEPT_CONTEXT)
Quando a função AcceptEx retorna, o soquete sAcceptSocket está no estado padrão de um soquete conectado. O soquete sAcceptSocket não herda as propriedades do soquete associado ao parâmetro sListenSocket até que SO_UPDATE_ACCEPT_CONTEXT seja definido no soquete. Use a função setsockopt para definir a opção SO_UPDATE_ACCEPT_CONTEXT, especificando sAcceptSocket como o identificador de soquete e sListenSocket como o valor da opção.
Por exemplo:
//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 um buffer de recebimento for fornecido, a operação sobreposta não será concluída até que uma conexão seja aceita e os dados sejam lidos. Use a função getsockopt com a opção SO_CONNECT_TIME para marcar se uma conexão foi aceita. Se ela tiver sido aceita, você poderá determinar por quanto tempo a conexão foi estabelecida. O valor retornado é o número de segundos que o soquete foi conectado. Se o soquete não estiver conectado, o getsockopt retornará 0xFFFFFFFF. Aplicativos que marcar se a operação sobreposta foi concluída, em combinação com a opção SO_CONNECT_TIME, podem determinar se uma conexão foi aceita, mas nenhum dado foi recebido. Examinar uma conexão dessa maneira permite que um aplicativo determine se as conexões que foram estabelecidas por um tempo não receberam dados. É recomendável que essas conexões sejam encerradas fechando o soquete aceito, o que força a chamada de função AcceptEx a ser concluída com um erro.
Por exemplo:
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: essa função tem suporte para aplicativos da Windows Phone Store no Windows Phone 8 e posterior.
Windows 8.1 e Windows Server 2012 R2: essa função tem suporte para aplicativos da Windows Store em Windows 8.1, Windows Server 2012 R2 e posteriores.
Código de exemplo
O exemplo a seguir usa a função AcceptEx usando portas de E/S sobrepostas e de conclusão.#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;
}
Notas para QoS
A função TransmitFile permite a configuração de dois sinalizadores, TF_DISCONNECT ou TF_REUSE_SOCKET, que retornam o soquete a um estado "desconectado e reutilizável" após a transmissão do arquivo. Esses sinalizadores não devem ser usados em um soquete em que a qualidade do serviço foi solicitada, pois o provedor de serviços pode excluir imediatamente qualquer qualidade de serviço associada ao soquete antes que a transferência de arquivo seja concluída. A melhor abordagem para um soquete habilitado para QoS é simplesmente chamar a função closesocket quando a transferência de arquivo for concluída, em vez de depender desses sinalizadores.Notas para caixa eletrônico
Há problemas importantes associados à configuração da conexão ao usar o ATM (Modo de Transferência Assíncrona) com o Windows Sockets 2. Consulte a seção Comentários na documentação aceitar função para obter informações importantes de configuração de conexão do ATM.Requisitos
Requisito | Valor |
---|---|
Cliente mínimo com suporte | Windows 8.1, Windows Vista [aplicativos da área de trabalho | Aplicativos UWP] |
Servidor mínimo com suporte | Windows Server 2003 [aplicativos da área de trabalho | Aplicativos UWP] |
Plataforma de Destino | Windows |
Cabeçalho | winsock.h (inclua Mswsock.h) |
Biblioteca | Mswsock.lib |
DLL | Mswsock.dll |