Função WSARecvFrom (winsock2.h)

A função WSARecvFrom recebe um datagrama e armazena o endereço de origem.

Sintaxe

int WSAAPI WSARecvFrom(
  [in]      SOCKET                             s,
  [in, out] LPWSABUF                           lpBuffers,
  [in]      DWORD                              dwBufferCount,
  [out]     LPDWORD                            lpNumberOfBytesRecvd,
  [in, out] LPDWORD                            lpFlags,
  [out]     sockaddr                           *lpFrom,
  [in, out] LPINT                              lpFromlen,
  [in]      LPWSAOVERLAPPED                    lpOverlapped,
  [in]      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

Parâmetros

[in] s

Um descritor que identifica um soquete.

[in, out] lpBuffers

Um ponteiro para uma matriz de estruturas WSABUF . Cada estrutura WSABUF contém um ponteiro para um buffer e o comprimento do buffer.

[in] dwBufferCount

O número de estruturas WSABUF na matriz lpBuffers .

[out] lpNumberOfBytesRecvd

Um ponteiro para o número de bytes recebidos por essa chamada se a operação WSARecvFrom 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 WSARecvFrom . Consulte os comentários abaixo.

[out] lpFrom

Um ponteiro opcional para um buffer que manterá o endereço de origem após a conclusão da operação sobreposta.

[in, out] lpFromlen

Um ponteiro para o tamanho, em bytes, do buffer "from" necessário somente se lpFrom for especificado.

[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 WSARecvFrom foi concluída (ignorado para soquetes não sobrepostos).

Valor retornado

Se nenhum erro ocorrer e a operação de recebimento for concluída imediatamente, WSARecvFrom 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 será retornado e um código de erro específico poderá 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
WSAECONNRESET
O circuito virtual foi redefinido pelo lado remoto executando um fechamento forçado ou por anulação. O aplicativo deve fechar o soquete porque ele não pode ser mais usado. Para um soquete de datagrama UPD, esse erro indicaria que uma operação de envio anterior resultou em uma mensagem "Porta Inacessível" ICMP.
WSAEFAULT
O parâmetro lpBuffers, lpFlags, lpFrom, lpNumberOfBytesRecvd, lpFromlen, lpOverlapped ou lpCompletionRoutine não está totalmente contido em uma parte válida do espaço de endereço do usuário: o buffer lpFrom era muito pequeno para acomodar o endereço par.
WSAEINPROGRESS
Uma chamada de bloqueio do Windows Sockets 1.1 está em andamento ou o provedor de serviços ainda está processando uma função de retorno de chamada.
WSAEINTR
Uma chamada de bloqueio do Windows Socket 1.1 foi cancelada por meio de WSACancelBlockingCall.
WSAEINVAL
O soquete não foi associado (com associação, por exemplo).
WSAEMSGSIZE
A mensagem era muito grande para o buffer especificado e (somente para protocolos não confiáveis) qualquer parte à direita da mensagem que não se encaixasse no buffer foi descartada.
WSAENETDOWN
O subsistema de rede falhou.
WSAENETRESET
Para um soquete de datagrama, este erro indica que a vida útil venceu.
WSAENOTCONN
O soquete não está conectado (somente soquetes orientados à conexão).
WSAEWOULDBLOCK
Windows NT:

Soquetes sobrepostos: há muitas solicitações de E/S sobrepostas pendentes. Soquetes não sobrepostos: o soquete é marcado como não desbloqueio e a operação de recebimento não pode ser concluída imediatamente.

WSANOTINITIALISED
Uma chamada WSAStartup bem-sucedida deve ocorrer antes de usar essa função.
WSA_IO_PENDING
Uma operação sobreposta foi iniciada com êxito e a conclusão será indicada posteriormente.
WSA_OPERATION_ABORTED
A operação sobreposta foi cancelada devido ao fechamento do soquete.

Comentários

A função WSARecvFrom fornece funcionalidade além da função recvfrom padrão em três áreas importantes:

  • Ele pode ser usado em conjunto com soquetes sobrepostos para executar operações de recebimento 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 é uma entrada e um parâmetro de saída, permitindo que os aplicativos sensoriem o estado de saída do bit do sinalizador MSG_PARTIAL . Lembre-se de que o bit do sinalizador MSG_PARTIAL não tem suporte de todos os protocolos.
A função WSARecvFrom é usada principalmente em um soquete sem conexão especificado por s. O endereço local do soquete deve ser conhecido. Para aplicativos de servidor, isso geralmente é feito explicitamente por meio da associação. A associação explícita é desencorajada para aplicativos cliente. Para aplicativos cliente que usam essa função, o soquete pode se tornar implicitamente associado a um endereço local por meio de sendto, WSASendTo ou WSAJoinLeaf.

Para soquetes sobrepostos, essa função é usada para postar um ou mais buffers nos quais os dados de entrada serão colocados à medida que ficam disponíveis em um soquete (possivelmente conectado), após o qual ocorre 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. Além disso, os valores indicados por lpFrom e lpFromlen não são atualizados até que a conclusão seja indicada. Os aplicativos não devem usar ou perturbar esses valores até que tenham sido atualizados; portanto, o aplicativo não deve usar variáveis automáticas (ou seja, baseadas em pilha) para esses parâmetros.

Nota Todas as E/S iniciadas por um determinado thread são canceladas quando esse thread é encerrado. Para soquetes sobrepostos, as operações assíncronas pendentes poderão falhar se o thread for fechado antes da conclusão das operações. Consulte ExitThread para obter mais informações.
 
Se lpOverlapped e lpCompletionRoutine forem NULL, o soquete nessa função será tratado como um soquete não sobreposto.

Para soquetes não sobrepostos, a semântica de bloqueio é idêntica à da função WSARecv 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 para os buffers do usuário. Para o 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.

Os buffers são preenchidos na ordem em que aparecem na matriz indicada 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 tipos de soquete sem conexão, o endereço do qual os dados se originaram é copiado para o buffer indicado por lpFrom. O valor apontado por lpFromlen é inicializado para o tamanho desse buffer e é modificado após a conclusão para indicar o tamanho real do endereço armazenado lá. Conforme mencionado anteriormente para soquetes sobrepostos, os parâmetros lpFrom e lpFromlen não são atualizados até que a E/S sobreposta seja concluída. A memória apontada por esses parâmetros deve, portanto, permanecer disponível para o provedor de serviços e não pode ser alocada no quadro de pilha do aplicativo. Os parâmetros lpFrom e lpFromlen são ignorados para soquetes orientados à conexão.

Para soquetes de estilo de fluxo de bytes (por exemplo, digite SOCK_STREAM), os dados de entrada são colocados nos buffers até:

  • Os buffers são preenchidos.
  • A conexão está fechada.
  • Os dados armazenados em buffer internamente são 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, 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 WSARecvFrom 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), o excesso de dados é perdido e WSARecvFrom gera o erro WSAEMSGSIZE.

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 Visualiza 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 são uma parte da mensagem transmitida pelo remetente. Partes restantes da mensagem serão transmitidas em operações de recebimento subsequentes. Uma operação de recebimento subsequente com MSG_PARTIAL sinalizador limpo indica o fim da mensagem do remetente.

Como 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 serviços.

 

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á desmarcada em lpFlags. No caso de conclusão atrasada, o valor apontado por lpFlags não é atualizado. Quando a conclusão for indicada, o aplicativo deve chamar WSAGetOverlappedResult e examinar os sinalizadores apontados pelo parâmetro lpdwFlags .

Nota Ao emitir uma chamada winsock de bloqueio, como WSARecvFrom com o parâmetro lpOverlapped definido como NULL, Winsock pode precisar aguardar um evento de rede antes que a chamada possa ser concluída. O Winsock executa uma espera alertável nessa situação, que pode ser interrompida por uma APC (chamada de procedimento assíncrona) agendada no mesmo thread. Emitir outra chamada winsock de bloqueio dentro de um APC que interrompeu uma chamada Winsock de bloqueio contínuo no mesmo thread levará a um comportamento indefinido e nunca deve ser tentado pelos clientes winsock.
 

E/S de soquete sobreposto

Se uma operação sobreposta for concluída imediatamente, WSARecvFrom 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 apontados pelo parâmetro lpFlags também serão atualizados . Se a operação sobreposta for iniciada com êxito e for concluída posteriormente, WSARecvFrom 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 conclui, 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 por meio do parâmetro dwFlags da rotina de conclusão ou examinando o parâmetro lpdwFlags de WSAGetOverlappedResult.

A função WSARecvFrom 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 em 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 simultaneamente pendentes, 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 chama posteriormente 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 tentar 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 invocada.

Se uma porta de conclusão de E/S for usada e o parâmetro lpCompletionRoutine e o parâmetro hEvent forem NULL, o resultado da operação será agendado na porta de conclusão de E/S. Isso acontece para todas as operações bem-sucedidas, sejam elas concluídas imediatamente ou não.

Os provedores de transporte permitem que um aplicativo invoque operações de envio e recebimento de dentro do contexto da rotina de conclusão de E/S do soquete e garantam que, 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 em um contexto preemptivo.

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 cbTransferred especifica o número de bytes recebidos. O parâmetro dwFlags contém informações que teriam sido exibidas em lpFlags se a operação de recebimento tivesse sido concluída imediatamente. Essa função não retorna um valor.

Retornar 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 atendida 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 especificada.

Código de exemplo

O exemplo a seguir demonstra o uso da função WSARecvFrom .
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

int __cdecl main()
{

    WSADATA wsaData;
    WSABUF DataBuf;
    WSAOVERLAPPED Overlapped;

    SOCKET RecvSocket = INVALID_SOCKET;
    struct sockaddr_in RecvAddr;
    struct sockaddr_in SenderAddr;

    int SenderAddrSize = sizeof (SenderAddr);
    u_short Port = 27015;

    char RecvBuf[1024];
    int BufLen = 1024;
    DWORD BytesRecv = 0;
    DWORD Flags = 0;

    int err = 0;
    int rc;
    int retval = 0;
    
    //-----------------------------------------------
    // Initialize Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc != 0) {
        /* Could not find a usable Winsock DLL */
        wprintf(L"WSAStartup failed with error: %ld\n", rc);
        return 1;
    }

    // Make sure the Overlapped struct is zeroed out
    SecureZeroMemory((PVOID) &Overlapped, sizeof(WSAOVERLAPPED) );

    // Create an event handle and setup the overlapped structure.
    Overlapped.hEvent = WSACreateEvent();
    if (Overlapped.hEvent == NULL) {
        wprintf(L"WSACreateEvent failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    RecvSocket = WSASocket(AF_INET,
                           SOCK_DGRAM,
                           IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);

    if (RecvSocket == INVALID_SOCKET) {
        /* Could not open a socket */
        wprintf(L"WSASocket failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    rc = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    if (rc != 0) {
        /* Bind to the socket failed */
        wprintf(L"bind failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        closesocket(RecvSocket);
        WSACleanup();
        return 1;
    }

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    DataBuf.len = BufLen;
    DataBuf.buf = RecvBuf;
    wprintf(L"Listening for incoming datagrams on port=%d\n", Port);
    rc = WSARecvFrom(RecvSocket,
                      &DataBuf,
                      1,
                      &BytesRecv,
                      &Flags,
                      (SOCKADDR *) & SenderAddr,
                      &SenderAddrSize, &Overlapped, NULL);

    if (rc != 0) {
        err = WSAGetLastError();
        if (err != WSA_IO_PENDING) {
            wprintf(L"WSARecvFrom failed with error: %ld\n", err);
            WSACloseEvent(Overlapped.hEvent);
            closesocket(RecvSocket);
            WSACleanup();
            return 1;
        }
        else {
            rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
            if (rc == WSA_WAIT_FAILED) {
                wprintf(L"WSAWaitForMultipleEvents failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }

            rc = WSAGetOverlappedResult(RecvSocket, &Overlapped, &BytesRecv,
                                FALSE, &Flags);
            if (rc == FALSE) {
                wprintf(L"WSArecvFrom failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }
            else
                wprintf(L"Number of received bytes = %d\n", BytesRecv);
                
            wprintf(L"Finished receiving. Closing socket.\n");
        }
        
    }
    //---------------------------------------------
    // When the application is finished receiving, close the socket.

    WSACloseEvent(Overlapped.hEvent);
    closesocket(RecvSocket);
    wprintf(L"Exiting.\n");

    //---------------------------------------------
    // Clean up and quit.
    WSACleanup();
    return (retval);
}

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

Confira também

WSABUF

WSACloseEvent

Wsacreateevent

Wsagetoverlappedresult

WSAOVERLAPPED

WSASend

WSASendTo

Wsasocket

WSAWaitForMultipleEvents

Funções Winsock

Referência de Winsock

Sendto