Função WSARecv (winsock2.h)
A função WSARecv recebe dados de um soquete conectado ou de um soquete sem conexão associado.
Sintaxe
int WSAAPI WSARecv(
[in] SOCKET s,
[in, out] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesRecvd,
[in, out] LPDWORD lpFlags,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Parâmetros
[in] s
Um descritor que identifica um soquete conectado.
[in, out] lpBuffers
Um ponteiro para uma matriz de estruturas WSABUF . Cada estrutura WSABUF contém um ponteiro para um buffer e o comprimento, em bytes, do buffer.
[in] dwBufferCount
O número de estruturas WSABUF na matriz lpBuffers .
[out] lpNumberOfBytesRecvd
Um ponteiro para o número, em bytes, de dados recebidos por essa chamada se a operação de recebimento for concluída imediatamente.
Use NULL para esse parâmetro se o parâmetro lpOverlapped não for NULL para evitar resultados potencialmente incorretos. Esse parâmetro só poderá ser NULL se o parâmetro lpOverlapped não for NULL.
[in, out] lpFlags
Um ponteiro para sinalizadores usados para modificar o comportamento da chamada de função WSARecv . Para obter mais informações, consulte a seção Comentários.
[in] lpOverlapped
Um ponteiro para uma estrutura WSAOVERLAPPED (ignorado para soquetes não sobrepostos).
[in] lpCompletionRoutine
Tipo: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
Um ponteiro para a rotina de conclusão chamado quando a operação de recebimento foi concluída (ignorado para soquetes não sobrepostos).
Valor retornado
Se nenhum erro ocorrer e a operação de recebimento tiver sido concluída imediatamente, WSARecv retornará zero. Nesse caso, a rotina de conclusão já terá sido agendada para ser chamada quando o thread de chamada estiver no estado alertável. Caso contrário, um valor de SOCKET_ERROR é retornado e um código de erro específico pode ser recuperado chamando WSAGetLastError. O código de erro WSA_IO_PENDING indica que a operação sobreposta foi iniciada com êxito e que a conclusão será indicada posteriormente. Qualquer outro código de erro indica que a operação sobreposta não foi iniciada com êxito e nenhuma indicação de conclusão ocorrerá.
Código do erro | Significado |
---|---|
O circuito virtual foi encerrado por causa do tempo limite ou outra falha. | |
Para um soquete de fluxo, o circuito virtual foi redefinido pelo lado remoto. O aplicativo deve fechar o soquete porque ele não pode ser mais usado. Para um soquete de datagrama UDP, esse erro indicaria que uma operação de envio anterior resultou em uma mensagem "Porta Inacessível" do ICMP. | |
Soquete é orientado a mensagens e o circuito virtual foi normalmente fechado pelo lado remoto. | |
O parâmetro lpBuffers não está completamente contido em uma parte válida do espaço de endereço do usuário. | |
Uma chamada do Windows Sockets 1.1 de bloqueio está em andamento ou o provedor de serviços ainda está processando uma função de retorno de chamada. | |
A chamada (bloqueio) foi cancelada pela função WSACancelBlockingCall . | |
O soquete não foi associado (por exemplo, com associação). | |
A mensagem era muito grande para caber no buffer especificado e (somente para protocolos não confiáveis) qualquer parte à direita da mensagem que não se encaixasse no buffer foi descartada. | |
O subsistema de rede falhou. | |
Para um soquete orientado à conexão, esse erro indica que a conexão foi interrompida devido à atividade keep alive que detectou uma falha enquanto a operação estava em andamento. Para um soquete de datagrama, este erro indica que a vida útil venceu. | |
O soquete não está conectado. | |
O descritor não é um soquete. | |
MSG_OOB foi especificado, mas o soquete não é estilo de fluxo, como tipo SOCK_STREAM, os dados OOB não têm suporte no domínio de comunicação associado a esse soquete ou o soquete é unidirecional e dá suporte apenas a operações de envio. | |
O soquete foi desligado; Não é possível chamar WSARecv em um soquete após o desligamento ter sido invocado com a definiçãode como SD_RECEIVE ou SD_BOTH. | |
A conexão foi cancelada porque houve falha na rede ou porque o sistema falhou ao responder ao peer system. | |
Windows NT: Soquetes sobrepostos: há muitas solicitações de E/S sobrepostas pendentes. Soquetes não sobrepostos: o soquete é marcado como não desbloqueado e a operação de recebimento não pode ser concluída imediatamente. |
|
Uma chamada WSAStartup bem-sucedida deve ocorrer antes de usar essa função. | |
Uma operação sobreposta foi iniciada com êxito e a conclusão será indicada posteriormente. | |
A operação sobreposta foi cancelada devido ao fechamento do soquete. |
Comentários
A função WSARecv fornece alguns recursos adicionais em comparação com a função recv padrão em três áreas importantes:
- Ele pode ser usado em conjunto com soquetes sobrepostos para executar operações recv sobrepostas.
- Ele permite que vários buffers de recebimento sejam especificados, tornando-o aplicável ao tipo de E/S de dispersão/coleta.
- O parâmetro lpFlags é usado na entrada e retornado na saída, permitindo que os aplicativos sensoriem o estado de saída do bit de sinalizador MSG_PARTIAL . No entanto, o bit de sinalizador MSG_PARTIAL não é suportado por todos os protocolos.
Para soquetes conectados e sem conexão, essa função restringe os endereços dos quais as mensagens recebidas são aceitas. A função retorna apenas mensagens do endereço remoto especificado na conexão. As mensagens de outros endereços são (silenciosamente) descartadas.
Para soquetes sobrepostos, o WSARecv é usado para postar um ou mais buffers nos quais os dados de entrada serão colocados à medida que estiverem disponíveis, após o qual ocorrerá a indicação de conclusão especificada pelo aplicativo (invocação da rotina de conclusão ou configuração de um objeto de evento). Se a operação não for concluída imediatamente, o status de conclusão final será recuperado por meio da rotina de conclusão ou WSAGetOverlappedResult.
Para soquetes não sobrepostos, a semântica de bloqueio é idêntica à da função recv padrão e os parâmetros lpOverlapped e lpCompletionRoutine são ignorados. Todos os dados que já foram recebidos e armazenados em buffer pelo transporte serão copiados nos buffers de usuário especificados. No caso de um soquete de bloqueio sem dados recebidos e armazenados em buffer pelo transporte, a chamada será bloqueada até que os dados sejam recebidos. O Windows Sockets 2 não define nenhum mecanismo de tempo limite de bloqueio padrão para essa função. Para protocolos que atuam como protocolos de fluxo de bytes, a pilha tenta retornar o máximo de dados possível sujeito ao espaço de buffer disponível e à quantidade de dados recebidos disponíveis. No entanto, o recebimento de um único byte é suficiente para desbloquear o chamador. Não há nenhuma garantia de que mais de um único byte será retornado. Para protocolos que atuam como orientados a mensagens, uma mensagem completa é necessária para desbloquear o chamador.
XP1_MESSAGE_ORIENTED | XP1_PSEUDO_STREAM | MSG_PARTIAL | Atua como |
---|---|---|---|
não definido | * | * | Fluxo de bytes |
* | Definir | * | Fluxo de bytes |
set | Não definido | set | Fluxo de bytes |
set | Não definido | não definido | Orientado a mensagens |
Os buffers são preenchidos na ordem em que aparecem na matriz apontada por lpBuffers e os buffers são empacotados para que nenhum orifício seja criado.
Se essa função for concluída de maneira sobreposta, será responsabilidade do provedor de serviços Winsock capturar as estruturas WSABUF antes de retornar dessa chamada. Isso permite que os aplicativos criem matrizes WSABUF baseadas em pilha apontadas pelo parâmetro lpBuffers .
Para soquetes no estilo de fluxo de bytes (por exemplo, tipo SOCK_STREAM), os dados de entrada são colocados nos buffers até que os buffers sejam preenchidos, a conexão seja fechada ou os dados armazenados em buffer internamente sejam esgotados. Independentemente de os dados de entrada preencherem ou não todos os buffers, a indicação de conclusão ocorre para soquetes sobrepostos.
Para soquetes orientados a mensagens (por exemplo, digite SOCK_DGRAM), uma mensagem de entrada é colocada nos buffers até o tamanho total dos buffers e a indicação de conclusão ocorre para soquetes sobrepostos. Se a mensagem for maior que os buffers, os buffers serão preenchidos com a primeira parte da mensagem. Se o recurso MSG_PARTIAL tiver suporte do provedor de serviços subjacente, o sinalizador MSG_PARTIAL será definido em lpFlags e as operações de recebimento subsequentes recuperarão o restante da mensagem. Se MSG_PARTIAL não tiver suporte, mas o protocolo for confiável, o WSARecv gerará o erro WSAEMSGSIZE e uma operação de recebimento subsequente com um buffer maior poderá ser usada para recuperar toda a mensagem. Caso contrário, (ou seja, o protocolo não é confiável e não dá suporte a MSG_PARTIAL), os dados em excesso são perdidos e o WSARecv gera o erro WSAEMSGSIZE.
Para soquetes orientados à conexão, o WSARecv pode indicar o encerramento normal do circuito virtual de uma das duas maneiras que dependem se o soquete é orientado a fluxo de bytes ou mensagem. Para fluxos de bytes, zero bytes que foram lidos (conforme indicado por um valor de retorno zero para indicar êxito e o valor lpNumberOfBytesRecvd de zero) indica um fechamento normal e que nenhum bytes será lido. Para soquetes orientados a mensagens, em que uma mensagem de byte zero geralmente é permitida, uma falha com um código de erro de WSAEDISCON é usada para indicar um fechamento normal. De qualquer forma, um código de erro de retorno de WSAECONNRESET indica que ocorreu um fechamento abortivo.
O parâmetro lpFlags pode ser usado para influenciar o comportamento da invocação de função além das opções especificadas para o soquete associado. Ou seja, a semântica dessa função é determinada pelas opções de soquete e pelo parâmetro lpFlags . Este último é construído usando o operador OR bit a bit com qualquer um dos valores listados na tabela a seguir.
Valor | Significado |
---|---|
MSG_PEEK |
Espia os dados de entrada. Os dados são copiados para o buffer, mas não são removidos da fila de entrada.
Esse sinalizador é válido apenas para soquetes não sobrepostos. |
MSG_OOB | Processa dados OOB. |
MSG_PARTIAL |
Esse sinalizador destina-se apenas a soquetes orientados a mensagens. Na saída, esse sinalizador indica que os dados especificados são uma parte da mensagem transmitida pelo remetente. As partes restantes da mensagem serão especificadas nas operações de recebimento subsequentes. Uma operação de recebimento subsequente com o sinalizador MSG_PARTIAL limpo indica o fim da mensagem do remetente.
Como um parâmetro de entrada, esse sinalizador indica que a operação de recebimento deve ser concluída mesmo que apenas parte de uma mensagem tenha sido recebida pelo provedor de transporte. |
MSG_PUSH_IMMEDIATE |
Esse sinalizador destina-se apenas a soquetes orientados a fluxo. Esse sinalizador permite que um aplicativo que usa soquetes de fluxo informe ao provedor de transporte para não atrasar a conclusão de solicitações de recebimento pendentes parcialmente preenchidas. Essa é uma dica para o provedor de transporte de que o aplicativo está disposto a receber quaisquer dados de entrada o mais rápido possível sem necessariamente esperar pelo restante dos dados que ainda podem estar em trânsito. O que constitui uma solicitação de recebimento pendente parcialmente preenchida é uma questão específica do transporte.
No caso do TCP, isso se refere ao caso de segmentos TCP de entrada sendo colocados no buffer de dados de solicitação de recebimento em que nenhum dos segmentos TCP indicou um valor de bit push de 1. Nesse caso, o TCP pode manter a solicitação de recebimento parcialmente preenchida um pouco mais para permitir que o restante dos dados chegue com um segmento TCP que tenha o bit PUSH definido como 1. Esse sinalizador informa ao TCP para não manter a solicitação de recebimento, mas para concluí-la imediatamente. O uso desse sinalizador para transferências de blocos grandes não é recomendado, pois o processamento de blocos parciais geralmente não é ideal. Esse sinalizador é útil apenas para casos em que receber e processar os dados parciais imediatamente ajuda a diminuir a latência de processamento. Esse sinalizador é uma dica em vez de uma garantia real. Esse sinalizador tem suporte no Windows 8.1, no Windows Server 2012 R2 e posterior. |
MSG_WAITALL |
A solicitação de recebimento será concluída somente quando ocorrer um dos seguintes eventos:
Lembre-se de que, se o provedor de transporte subjacente não der suporte a MSG_WAITALL ou se o soquete estiver em um modo sem bloqueio, essa chamada falhará com WSAEOPNOTSUPP. Além disso, se MSG_WAITALL for especificado junto com MSG_OOB, MSG_PEEK ou MSG_PARTIAL, essa chamada falhará com WSAEOPNOTSUPP. Não há suporte para esse sinalizador em soquetes de datagrama ou soquetes orientados a mensagens. |
Para soquetes orientados a mensagens, o bit MSG_PARTIAL será definido no parâmetro lpFlags se uma mensagem parcial for recebida. Se uma mensagem completa for recebida, MSG_PARTIAL será limpa em lpFlags. No caso de conclusão atrasada, o valor apontado por lpFlags não é atualizado. Quando a conclusão for indicada, o aplicativo deverá chamar WSAGetOverlappedResult e examinar os sinalizadores indicados pelo parâmetro lpdwFlags .
E/S de soquete sobreposta
Se uma operação sobreposta for concluída imediatamente, WSARecv retornará um valor igual a zero e o parâmetro lpNumberOfBytesRecvd será atualizado com o número de bytes recebidos e os bits de sinalizador indicados pelo parâmetro lpFlags também serão atualizados . Se a operação sobreposta for iniciada com êxito e for concluída posteriormente, o WSARecv retornará SOCKET_ERROR e indicará o código de erro WSA_IO_PENDING. Nesse caso, lpNumberOfBytesRecvd e lpFlags não são atualizados . Quando a operação sobreposta é concluída, a quantidade de dados transferidos é indicada por meio do parâmetro cbTransferred na rotina de conclusão (se especificada) ou por meio do parâmetro lpcbTransfer em WSAGetOverlappedResult. Os valores de sinalizador são obtidos examinando o parâmetro lpdwFlags de WSAGetOverlappedResult.A função WSARecv usando E/S sobreposta pode ser chamada de dentro da rotina de conclusão de uma função WSARecv, WSARecvFrom, WSASend ou WSASendTo anterior. Para um determinado soquete, as rotinas de conclusão de E/S não serão aninhadas. Isso permite que transmissões de dados sensíveis ao tempo ocorram inteiramente dentro de um contexto preemptivo.
O parâmetro lpOverlapped deve ser válido durante a operação sobreposta. Se várias operações de E/S estiverem pendentes simultaneamente, cada uma deverá referenciar uma estrutura WSAOVERLAPPED separada.
Se o parâmetro lpCompletionRoutine for NULL, o parâmetro hEvent de lpOverlapped será sinalizado quando a operação sobreposta for concluída se contiver um identificador de objeto de evento válido. Um aplicativo pode usar WSAWaitForMultipleEvents ou WSAGetOverlappedResult para aguardar ou sondar o objeto de evento.
Se lpCompletionRoutine não for NULL, o parâmetro hEvent será ignorado e poderá ser usado pelo aplicativo para passar informações de contexto para a rotina de conclusão. Um chamador que passa um lpCompletionRoutine não NULL e, posteriormente, chama WSAGetOverlappedResult para a mesma solicitação de E/S sobreposta pode não definir o parâmetro fWait para essa invocação de WSAGetOverlappedResult como TRUE. Nesse caso, o uso do parâmetro hEvent é indefinido e a tentativa de aguardar o parâmetro hEvent produziria resultados imprevisíveis.
A rotina de conclusão segue as mesmas regras estipuladas para rotinas de conclusão de E/S de arquivo do Windows. A rotina de conclusão não será invocada até que o thread esteja em um estado de espera alertável, como pode ocorrer quando a função WSAWaitForMultipleEvents com o parâmetro fAlertable definido como TRUE for invocado.
O protótipo da rotina de conclusão é o seguinte:
void CALLBACK CompletionROUTINE(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
CompletionRoutine é um espaço reservado para um nome de função definido pelo aplicativo ou definido pela biblioteca. O dwError especifica o status de conclusão para a operação sobreposta, conforme indicado por lpOverlapped. O parâmetro cbTransferred especifica o número de bytes recebidos. O parâmetro dwFlags contém informações que teriam aparecido em lpFlags se a operação de recebimento tivesse sido concluída imediatamente. Essa função não retorna um valor.
O retorno dessa função permite a invocação de outra rotina de conclusão pendente para esse soquete. Ao usar WSAWaitForMultipleEvents, todas as rotinas de conclusão de espera são chamadas antes que a espera do thread alertável seja satisfeita com um código de retorno de WSA_IO_COMPLETION. As rotinas de conclusão podem ser chamadas em qualquer ordem, não necessariamente na mesma ordem em que as operações sobrepostas são concluídas. No entanto, os buffers postados têm a garantia de serem preenchidos na mesma ordem em que são especificados.
Se você estiver usando portas de conclusão de E/S, lembre-se de que a ordem das chamadas feitas ao WSARecv também é a ordem na qual os buffers são preenchidos. O WSARecv não deve ser chamado no mesmo soquete simultaneamente de threads diferentes, pois pode resultar em uma ordem de buffer imprevisível.
Código de exemplo
O exemplo a seguir mostra como usar a função WSARecv no modo de E/S sobreposto.#ifndef UNICODE
#define UNICODE
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable: 4127) // Conditional expression is a constant
#define DATA_BUFSIZE 4096
int __cdecl main(int argc, char **argv)
{
WSADATA wsd;
struct addrinfo *result = NULL, *ptr = NULL, hints;
WSAOVERLAPPED RecvOverlapped;
SOCKET ConnSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD RecvBytes, Flags;
char buffer[DATA_BUFSIZE];
int err = 0;
int rc;
if (argc != 2) {
wprintf(L"usage: %s server-name\n", argv[0]);
return 1;
}
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0) {
wprintf(L"Unable to load Winsock: %d\n", rc);
return 1;
}
// Make sure the hints struct is zeroed out
SecureZeroMemory((PVOID) & hints, sizeof (struct addrinfo));
// Initialize the hints to retrieve the server address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo(argv[1], "27015", &hints, &result);
if (rc != 0) {
wprintf(L"getaddrinfo failed with error: %d\n", rc);
return 1;
}
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
ConnSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
return 1;
}
rc = connect(ConnSocket, ptr->ai_addr, (int) ptr->ai_addrlen);
if (rc == SOCKET_ERROR) {
if (WSAECONNREFUSED == (err = WSAGetLastError())) {
closesocket(ConnSocket);
ConnSocket = INVALID_SOCKET;
continue;
}
wprintf(L"connect failed with error: %d\n", err);
freeaddrinfo(result);
closesocket(ConnSocket);
return 1;
}
break;
}
if (ConnSocket == INVALID_SOCKET) {
wprintf(L"Unable to establish connection with the server!\n");
freeaddrinfo(result);
return 1;
}
wprintf(L"Client connected...\n");
// Make sure the RecvOverlapped struct is zeroed out
SecureZeroMemory((PVOID) & RecvOverlapped, sizeof (WSAOVERLAPPED));
// Create an event handle and setup an overlapped structure.
RecvOverlapped.hEvent = WSACreateEvent();
if (RecvOverlapped.hEvent == NULL) {
wprintf(L"WSACreateEvent failed: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ConnSocket);
return 1;
}
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
// Call WSARecv until the peer closes the connection
// or until an error occurs
while (1) {
Flags = 0;
rc = WSARecv(ConnSocket, &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
wprintf(L"WSARecv failed with error: %d\n", err);
break;
}
rc = WSAWaitForMultipleEvents(1, &RecvOverlapped.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED) {
wprintf(L"WSAWaitForMultipleEvents failed with error: %d\n", WSAGetLastError());
break;
}
rc = WSAGetOverlappedResult(ConnSocket, &RecvOverlapped, &RecvBytes, FALSE, &Flags);
if (rc == FALSE) {
wprintf(L"WSARecv operation failed with error: %d\n", WSAGetLastError());
break;
}
wprintf(L"Read %d bytes\n", RecvBytes);
WSAResetEvent(RecvOverlapped.hEvent);
// If 0 bytes are received, the connection was closed
if (RecvBytes == 0)
break;
}
WSACloseEvent(RecvOverlapped.hEvent);
closesocket(ConnSocket);
freeaddrinfo(result);
WSACleanup();
return 0;
}
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 posterior.
Requisitos
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 | winsock2.h |
Biblioteca | Ws2_32.lib |
DLL | Ws2_32.dll |