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 |
---|---|
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". | |
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. | |
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. | |
Se canceló una llamada de Bloqueo de Windows Socket 1.1 a través de WSACancelBlockingCall. | |
El socket no se ha enlazado (por ejemplo, con enlace). | |
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. | |
Error en el subsistema de red. | |
Para un socket de datagrama, este error indica que expiró el tiempo de vida. | |
El socket no está conectado (solo sockets orientados a la conexión). | |
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. |
|
Debe producirse una llamada de WSAStartup correcta antes de usar esta función. | |
Una operación superpuesta se inició correctamente y la finalización se indicará más adelante. | |
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.
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.
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.
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 .
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 |