Función WSARecvFrom (winsock2.h)

La función WSARecvFrom recibe un datagrama y almacena la dirección de origen.

Sintaxis

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

Descriptor que identifica un socket.

[in, out] lpBuffers

Puntero a una matriz de estructuras WSABUF . Cada estructura WSABUF contiene un puntero a un búfer y la longitud del búfer.

[in] dwBufferCount

Número de estructuras WSABUF en la matriz lpBuffers .

[out] lpNumberOfBytesRecvd

Puntero al número de bytes recibidos por esta llamada si la operación WSARecvFrom se completa inmediatamente.

Use NULL para este parámetro si el parámetro lpOverlapped no es NULL para evitar resultados potencialmente erróneos. Este parámetro solo puede ser NULL si el parámetro lpOverlapped no es NULL.

[in, out] lpFlags

Puntero a marcas usadas para modificar el comportamiento de la llamada de función WSARecvFrom . Vea los comentarios más abajo.

[out] lpFrom

Puntero opcional a un búfer que contendrá la dirección de origen tras la finalización de la operación superpuesta.

[in, out] lpFromlen

Puntero al tamaño, en bytes, del búfer "from" necesario solo si se especifica lpFrom .

[in] lpOverlapped

Puntero a una estructura WSAOVERLAPPED (omitida para sockets no superpuestos).

[in] lpCompletionRoutine

Tipo: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

Puntero a la rutina de finalización a la que se llama cuando se ha completado la operación WSARecvFrom (se omite para sockets no superpuestos).

Valor devuelto

Si no se produce ningún error y la operación de recepción se ha completado inmediatamente, WSARecvFrom devuelve cero. En este caso, la rutina de finalización ya se habrá programado para llamarse una vez que el subproceso de llamada esté en estado de alerta. De lo contrario, se devuelve un valor de SOCKET_ERROR y se puede recuperar un código de error específico llamando a WSAGetLastError. El código de error WSA_IO_PENDING indica que la operación superpuesta se ha iniciado correctamente y que la finalización se indicará más adelante. Cualquier otro código de error indica que la operación superpuesta no se inició correctamente y no se producirá ninguna indicación de finalización.

Código de error Significado
WSAECONNRESET
El lado remoto que ejecuta un cierre firme o de anulación restableció el circuito virtual. La aplicación debería cerrar el socket porque ya no se puede usar. En el caso de un socket de datagrama UPD, este error indicaría que una operación de envío anterior dio como resultado un mensaje icMP "Puerto inaccesible".
WSAEFAULT
El parámetro lpBuffers, lpFlags, lpFrom, lpNumberOfBytesRecvd, lpFromlen, lpOverlapped o lpCompletionRoutine no está totalmente incluido en una parte válida del espacio de direcciones del usuario: el búfer lpFrom era demasiado pequeño para acomodar la dirección del mismo nivel.
WSAEINPROGRESS
Una llamada de Bloqueo de Windows Sockets 1.1 está en curso o el proveedor de servicios sigue procesando una función de devolución de llamada.
WSAEINTR
Se canceló una llamada de Bloqueo de Windows Socket 1.1 a través de WSACancelBlockingCall.
WSAEINVAL
El socket no se ha enlazado (por ejemplo, con enlace).
WSAEMSGSIZE
El mensaje era demasiado grande para el búfer especificado y (solo para protocolos no confiables) se ha descartado cualquier parte final del mensaje que no cabe en el búfer.
WSAENETDOWN
Error en el subsistema de red.
WSAENETRESET
Para un socket de datagrama, este error indica que expiró el tiempo de vida.
WSAENOTCONN
El socket no está conectado (solo sockets orientados a la conexión).
WSAEWOULDBLOCK
Windows NT:

Sockets superpuestos: hay demasiadas solicitudes de E/S superpuestas pendientes. Sockets no superpuestos: el socket se marca como no desbloqueado y la operación de recepción no se puede completar inmediatamente.

WSANOTINITIALISED
Debe producirse una llamada de WSAStartup correcta antes de usar esta función.
WSA_IO_PENDING
Una operación superpuesta se inició correctamente y la finalización se indicará más adelante.
WSA_OPERATION_ABORTED
La operación superpuesta se ha cancelado debido al cierre del socket.

Comentarios

La función WSARecvFrom proporciona funcionalidad sobre la función estándar recvfrom en tres áreas importantes:

  • Se puede usar junto con sockets superpuestos para realizar operaciones de recepción superpuestas.
  • Permite especificar varios búferes de recepción, lo que hace que sea aplicable al tipo de dispersión o recopilación de E/S.
  • El parámetro lpFlags es un parámetro de entrada y salida, lo que permite a las aplicaciones detectar el estado de salida del bit de marca de MSG_PARTIAL . Tenga en cuenta que el bit de marca de MSG_PARTIAL no es compatible con todos los protocolos.
La función WSARecvFrom se usa principalmente en un socket sin conexión especificado por s. La dirección local del socket debe conocerse. En el caso de las aplicaciones de servidor, normalmente esto se realiza explícitamente a través del enlace. No se recomienda el enlace explícito para las aplicaciones cliente. Para las aplicaciones cliente que usan esta función, el socket se puede enlazar implícitamente a una dirección local a través de sendto, WSASendTo o WSAJoinLeaf.

En el caso de los sockets superpuestos, esta función se usa para publicar uno o varios búferes en los que se colocarán los datos entrantes a medida que estén disponibles en un socket (posiblemente conectado), después de lo cual se produce la indicación de finalización especificada por la aplicación (invocación de la rutina de finalización o configuración de un objeto de evento). Si la operación no se completa inmediatamente, el estado de finalización final se recupera a través de la rutina de finalización o WSAGetOverlappedResult. Además, los valores indicados por lpFrom y lpFromlen no se actualizan hasta que se indique la finalización. Las aplicaciones no deben usar ni molestar estos valores hasta que se hayan actualizado; por lo tanto, la aplicación no debe usar variables automáticas (es decir, basadas en pila) para estos parámetros.

Nota Todas las E/S iniciadas por un subproceso determinado se cancelan cuando se cierra ese subproceso. En el caso de los sockets superpuestos, las operaciones asincrónicas pendientes pueden producir un error si el subproceso se cierra antes de que se completen las operaciones. Consulte ExitThread para obtener más información.
 
Si lpOverlapped y lpCompletionRoutine son NULL, el socket de esta función se tratará como un socket no superpuesto.

En el caso de los sockets no superpuestos, la semántica de bloqueo es idéntica a la de la función WSARecv estándar y los parámetros lpOverlapped y lpCompletionRoutine se omiten. Los datos que ya se hayan recibido y almacenado en búfer por el transporte se copiarán en los búferes de usuario. En el caso de un socket de bloqueo sin que el transporte haya recibido y almacenado en búfer ningún dato actualmente, la llamada se bloqueará hasta que se reciban los datos.

Los búferes se rellenan en el orden en que aparecen en la matriz indicada por lpBuffers, y los búferes se empaquetan para que no se creen agujeros.

Si esta función se completa de forma superpuesta, es responsabilidad del proveedor de servicios winsock capturar las estructuras WSABUF antes de volver de esta llamada. Esto permite a las aplicaciones compilar matrices WSABUF basadas en pila a las que apunta el parámetro lpBuffers .

En el caso de los tipos de socket sin conexión, la dirección de la que se originaron los datos se copia en el búfer indicado por lpFrom. El valor al que apunta lpFromlen se inicializa en el tamaño de este búfer y se modifica al finalizar para indicar el tamaño real de la dirección almacenada allí. Como se indicó anteriormente para sockets superpuestos, los parámetros lpFrom y lpFromlen no se actualizan hasta que se haya completado la E/S superpuesta. La memoria a la que apuntan estos parámetros debe permanecer disponible para el proveedor de servicios y no se puede asignar en el marco de pila de la aplicación. Los parámetros lpFrom y lpFromlen se omiten para los sockets orientados a la conexión.

En el caso de los sockets de estilo de secuencia de bytes (por ejemplo, escriba SOCK_STREAM), los datos entrantes se colocan en los búferes hasta que:

  • Los búferes se rellenan.
  • La conexión está cerrada.
  • Se agotan los datos almacenados internamente en búfer.
Independientemente de si los datos entrantes rellenan o no todos los búferes, la indicación de finalización se produce para sockets superpuestos. En el caso de los sockets orientados a mensajes, un mensaje entrante se coloca en los búferes hasta el tamaño total de los búferes y la indicación de finalización se produce para sockets superpuestos. Si el mensaje es mayor que los búferes, los búferes se rellenan con la primera parte del mensaje. Si el proveedor de servicios subyacente admite la característica MSG_PARTIAL , la marca MSG_PARTIAL se establece en lpFlags y las operaciones de recepción posteriores recuperarán el resto del mensaje. Si no se admite MSG_PARTIAL, pero el protocolo es confiable, WSARecvFrom genera el error WSAEMSGSIZE y se puede usar una operación de recepción posterior con un búfer mayor para recuperar todo el mensaje. De lo contrario, (es decir, el protocolo no es confiable y no admite MSG_PARTIAL), se pierden los datos excesivos y WSARecvFrom genera el error WSAEMSGSIZE.

El parámetro lpFlags se puede usar para influir en el comportamiento de la invocación de función más allá de las opciones especificadas para el socket asociado. Es decir, la semántica de esta función viene determinada por las opciones de socket y el parámetro lpFlags . Este último se construye mediante el operador OR bit a bit con cualquiera de los valores enumerados en la tabla siguiente.

Valor Significado
MSG_PEEK Previsualiza los datos entrantes. Los datos se copian en el búfer, pero no se quitan de la cola de entrada. Esta marca solo es válida para sockets no superpuestos.
MSG_OOB Procesa los datos de OOB.
MSG_PARTIAL Esta marca es solo para sockets orientados a mensajes. En la salida, esta marca indica que los datos son una parte del mensaje transmitido por el remitente. Las partes restantes del mensaje se transmitirán en las operaciones de recepción posteriores. Una operación de recepción posterior con MSG_PARTIAL marca desactivada indica el final del mensaje del remitente.

Como parámetro de entrada, esta marca indica que la operación de recepción debe completarse aunque solo el proveedor de servicios haya recibido parte de un mensaje.

 

En el caso de los sockets orientados a mensajes, el bit de MSG_PARTIAL se establece en el parámetro lpFlags si se recibe un mensaje parcial. Si se recibe un mensaje completo, MSG_PARTIAL se borra en lpFlags. En el caso de la finalización retrasada, el valor al que apunta lpFlags no se actualiza. Cuando se haya indicado que la finalización de la aplicación debe llamar a WSAGetOverlappedResult y examinar las marcas a las que apunta el parámetro lpdwFlags .

Nota Al emitir una llamada winsock de bloqueo como WSARecvFrom con el parámetro lpOverlapped establecido en NULL, Winsock puede necesitar esperar un evento de red antes de que se pueda completar la llamada. Winsock realiza una espera alertable en esta situación, que se puede interrumpir mediante una llamada de procedimiento asincrónica (APC) programada en el mismo subproceso. La emisión de otra llamada winsock de bloqueo dentro de un APC que interrumpió una llamada de Winsock de bloqueo en curso en el mismo subproceso provocará un comportamiento indefinido y los clientes winsock nunca deben intentarlo.
 

E/S de socket superpuesta

Si una operación superpuesta se completa inmediatamente, WSARecvFrom devuelve un valor de cero y el parámetro lpNumberOfBytesRecvd se actualiza con el número de bytes recibidos y los bits de marca señalados por el parámetro lpFlags también se actualizan. Si la operación superpuesta se inicia correctamente y se completará más adelante, WSARecvFrom devuelve SOCKET_ERROR e indica el código de error WSA_IO_PENDING. En este caso, lpNumberOfBytesRecvd y lpFlags no se actualizan. Cuando la operación superpuesta completa la cantidad de datos transferidos se indica a través del parámetro cbTransferred en la rutina de finalización (si se especifica) o mediante el parámetro lpcbTransfer en WSAGetOverlappedResult. Los valores de marca se obtienen a través del parámetro dwFlags de la rutina de finalización o examinando el parámetro lpdwFlags de WSAGetOverlappedResult.

Se puede llamar a la función WSARecvFrom desde dentro de la rutina de finalización de una función WSARecv, WSARecvFrom, WSASend o WSASendTo anterior. Para un socket determinado, las rutinas de finalización de E/S no se anidarán. Esto permite que las transmisiones de datos sensibles al tiempo se produzcan por completo dentro de un contexto preferente.

El parámetro lpOverlapped debe ser válido durante la operación superpuesta. Si hay varias operaciones de E/S pendientes simultáneamente, cada una debe hacer referencia a una estructura WSAOVERLAPPED independiente.

Si el parámetro lpCompletionRoutine es NULL, el parámetro hEvent de lpOverlapped se señala cuando se completa la operación superpuesta si contiene un identificador de objeto de evento válido. Una aplicación puede usar WSAWaitForMultipleEvents o WSAGetOverlappedResult para esperar o sondear en el objeto de evento.

Si lpCompletionRoutine no es NULL, el parámetro hEvent se omite y la aplicación puede usar para pasar información de contexto a la rutina de finalización. Un llamador que pasa un lpCompletionRoutine no NULL y, posteriormente, llama a WSAGetOverlappedResult para la misma solicitud de E/S superpuesta no puede establecer el parámetro fWait para esa invocación de WSAGetOverlappedResult en TRUE. En este caso, el uso del parámetro hEvent no está definido y el intento de esperar en el parámetro hEvent produciría resultados imprevisibles.

La rutina de finalización sigue las mismas reglas que se estipulan para las rutinas de finalización de E/S de archivos de Windows. La rutina de finalización no se invocará hasta que el subproceso se encuentra en un estado de espera alertable, como puede ocurrir cuando se invoca la función WSAWaitForMultipleEvents con el parámetro fAlertable establecido en TRUE .

Si se usa un puerto de finalización de E/S y el parámetro lpCompletionRoutine y el parámetro hEvent son NULL, el resultado de la operación se programa en el puerto de finalización de E/S. Esto sucede para todas las operaciones correctas, tanto si las operaciones se completan inmediatamente como si no.

Los proveedores de transporte permiten que una aplicación invoque operaciones de envío y recepción desde dentro del contexto de la rutina de finalización de E/S del socket y garantice que, para un socket determinado, las rutinas de finalización de E/S no se anidarán. Esto permite que las transmisiones de datos sensibles al tiempo se produzcan por completo dentro de un contexto preferente.

El prototipo de la rutina de finalización es el siguiente.


void CALLBACK CompletionROUTINE(
  IN DWORD dwError, 
  IN DWORD cbTransferred, 
  IN LPWSAOVERLAPPED lpOverlapped, 
  IN DWORD dwFlags
);

CompletionRoutine es un marcador de posición para un nombre de función definido por la aplicación o definido por la biblioteca. DwError especifica el estado de finalización de la operación superpuesta, como se indica en lpOverlapped. CbTransferred especifica el número de bytes recibidos. El parámetro dwFlags contiene información que habría aparecido en lpFlags si la operación de recepción se hubiera completado inmediatamente. Esta función no devuelve ningún valor.

La devolución de esta función permite la invocación de otra rutina de finalización pendiente para este socket. Cuando se usa WSAWaitForMultipleEvents, se llama a todas las rutinas de finalización en espera antes de que la espera del subproceso alertable esté satisfecho con un código de retorno de WSA_IO_COMPLETION. Se puede llamar a las rutinas de finalización en cualquier orden, no necesariamente en el mismo orden en que se completan las operaciones superpuestas. Sin embargo, se garantiza que los búferes publicados se rellenen en el mismo orden en que se especifican.

Código de ejemplo

En el ejemplo siguiente se muestra el uso de la función 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: esta función es compatible con las aplicaciones de Windows Phone Store en Windows Phone 8 y versiones posteriores.

Windows 8.1 y Windows Server 2012 R2: esta función es compatible con las aplicaciones de la Tienda Windows en Windows 8.1, Windows Server 2012 R2 y versiones posteriores.

Requisitos

   
Cliente mínimo compatible Windows 8.1, Windows Vista [aplicaciones de escritorio | Aplicaciones para UWP]
Servidor mínimo compatible Windows Server 2003 [aplicaciones de escritorio | aplicaciones para UWP]
Plataforma de destino Windows
Encabezado winsock2.h
Library Ws2_32.lib
Archivo DLL Ws2_32.dll

Consulte también

WSABUF

WSACloseEvent

WSACreateEvent

WSAGetOverlappedResult

WSAOVERLAPPED

WSASend

WSASendTo

WSASocket

WSAWaitForMultipleEvents

Funciones winsock

Referencia de Winsock

sendto