Función WSASendTo (winsock2.h)
La función WSASendTo envía datos a un destino específico mediante E/S superpuesta cuando corresponda.
Sintaxis
int WSAAPI WSASendTo(
[in] SOCKET s,
[in] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesSent,
[in] DWORD dwFlags,
[in] const sockaddr *lpTo,
[in] int iTolen,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Parámetros
[in] s
Descriptor que identifica un socket (posiblemente conectado).
[in] lpBuffers
Puntero a una matriz de estructuras WSABUF . Cada estructura WSABUF contiene un puntero a un búfer y la longitud del búfer, en bytes. Para una aplicación Winsock, una vez que se llama a la función WSASendTo , el sistema posee estos búferes y es posible que la aplicación no tenga acceso a ellos. Esta matriz debe permanecer válida durante la operación de envío.
[in] dwBufferCount
Número de estructuras WSABUF en la matriz lpBuffers .
[out] lpNumberOfBytesSent
Puntero al número de bytes enviados por esta llamada si la operación de E/S 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] dwFlags
Marcas usadas para modificar el comportamiento de la llamada de función WSASendTo .
[in] lpTo
Puntero opcional a la dirección del socket de destino en la estructura SOCKADDR .
[in] iTolen
Tamaño, en bytes, de la dirección en el parámetro lpTo .
[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 de envío (se omite para sockets no superpuestos).
Valor devuelto
Si no se produce ningún error y la operación de envío se ha completado inmediatamente, WSASendTo 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 |
---|---|
La dirección solicitada es una dirección de difusión, pero no se ha establecido la marca adecuada. | |
La dirección remota no es una dirección válida (como ADDR_ANY). | |
Las direcciones de la familia especificada no se pueden usar con este socket. | |
En el caso de un socket de datagrama UDP, este error indicaría que una operación de envío anterior dio lugar a un mensaje ICMP "Puerto inaccesible". | |
Se requiere una dirección de destino. | |
Los parámetros lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent o lpCompletionRoutine no forman parte del espacio de direcciones del usuario o el parámetro lpTo es demasiado pequeño. | |
Se intentó realizar una operación de socket a un host inalcanzable. | |
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 con el enlace o el socket no se crea con la marca superpuesta. | |
El socket está orientado a mensajes y el mensaje es mayor que el máximo admitido por el transporte subyacente. | |
Error en el subsistema de red. | |
Para un socket de datagrama, este error indica que expiró el tiempo de vida. | |
La red no se puede alcanzar desde este host en estos momentos. | |
El proveedor de Windows Sockets informa de un interbloqueo de búfer. | |
El socket no está conectado (solo sockets orientados a la conexión). | |
El descriptor no es un socket. | |
El socket se ha apagado; no es posible WSASendTo en un socket después de que se haya invocado el apagado con cómo se establece en SD_SEND o SD_BOTH. | |
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 envío 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á en un momento posterior. | |
La operación superpuesta se ha cancelado debido al cierre del socket o a la ejecución del comando SIO_FLUSH en WSAIoctl. |
Comentarios
La función WSASendTo proporciona características mejoradas sobre la función sendto estándar en dos áreas importantes:
- Se puede usar junto con sockets superpuestos para realizar operaciones de envío superpuestas.
- Permite especificar varios búferes de envío, lo que hace que sea aplicable al tipo de dispersión o recopilación de E/S.
En el caso de los sockets superpuestos (creados mediante WSASocket con marca WSA_FLAG_OVERLAPPED) el envío de datos usa E/S superpuesta, a menos que lpOverlapped y lpCompletionRoutine sean NULL en cuyo caso el socket se trata como un socket no superpuesto. Se producirá una indicación de finalización (invocando la rutina de finalización o la configuración de un objeto de evento) cuando el transporte haya consumido los búferes. 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.
En el caso de los sockets no superpuestos, se omiten los dos últimos parámetros (lpOverlapped, lpCompletionRoutine) y WSASendTo adopta la misma semántica de bloqueo que el envío. Los datos se copian de los búferes en el búfer de transporte. Si el socket no está desbloqueado y orientado al flujo, y no hay suficiente espacio en el búfer del transporte, WSASendTo devuelve solo con parte de los búferes de la aplicación que se han consumido. Dada la misma situación de búfer y un socket de bloqueo, WSASendTo se bloqueará hasta que se consuma todo el contenido del búfer de la aplicación.
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 .
Para los sockets orientados a mensajes, se debe tener cuidado de no superar el tamaño máximo del mensaje del transporte subyacente, que se puede obtener obteniendo el valor de la opción de socket SO_MAX_MSG_SIZE. Si los datos son demasiado largos para pasar de forma atómica a través del protocolo subyacente, se devuelve el error WSAEMSGSIZE y no se transmite ningún dato.
Si el socket no está enlazado, el sistema asigna valores únicos a la asociación local y el socket se marca como enlazado.
Si el socket está conectado, se puede usar la función getsockname para determinar la dirección IP local y el puerto asociados al socket.
Si el socket no está conectado,
La función getsockname se puede usar para determinar el número de puerto local asociado al socket, pero la dirección IP devuelta se establece en la dirección comodín del protocolo dado (por ejemplo, INADDR_ANY o "0.0.0.0". para IPv4 y IN6ADDR_ANY_INIT o "::" para IPv6).
La finalización correcta de un WSASendTo no indica que los datos se entregaron correctamente.
El parámetro dwFlags 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 dwFlags . Este último se construye mediante el operador OR bit a bit con cualquiera de los valores enumerados en la tabla siguiente.
Valor | Significado |
---|---|
MSG_DONTROUTE | Especifica que los datos no deben estar sujetos a enrutamiento. Un proveedor de servicios de Windows Socket puede optar por omitir esta marca. |
MSG_OOB | Enviar datos OOB (socket de estilo de flujo, como solo SOCK_STREAM ). |
MSG_PARTIAL | Especifica que lpBuffers solo contiene un mensaje parcial. Tenga en cuenta que los transportes que no admiten transmisiones de mensajes parciales devolverán el código de error WSAEOPNOTSUPP . |
E/S de socket superpuesta
Si una operación superpuesta se completa inmediatamente, WSASendTo devuelve un valor de cero y el parámetro lpNumberOfBytesSent se actualiza con el número de bytes enviados. Si la operación superpuesta se inicia correctamente y se completará más adelante, WSASendTo devuelve SOCKET_ERROR e indica el código de error WSA_IO_PENDING. En este caso, lpNumberOfBytesSent no se actualiza. 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.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 .
Los proveedores de transporte permiten a una aplicación invocar operaciones de envío y recepción desde dentro del contexto de la rutina de finalización de E/S de socket y garantizar 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
);
La función CompletionRoutine es un marcador de posición para un nombre de función definido por la aplicación o definido por la biblioteca. El parámetro dwError especifica el estado de finalización de la operación superpuesta, como se indica en lpOverlapped. El parámetro cbTransferred especifica el número de bytes enviados. Actualmente no hay ningún valor de marca definido y dwFlags será cero. 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. 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 el que se completan las operaciones superpuestas. Sin embargo, se garantiza que los búferes publicados se envíen en el mismo orden en que se especifican.
Código de ejemplo
En el ejemplo siguiente se muestra el uso de la función WSASendTo mediante un objeto de evento.#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
int __cdecl main(int argc, char **argv)
{
//---------------------------------------------
// Declare and initialize variables
WSADATA wsaData;
WSABUF DataBuf;
WSAOVERLAPPED Overlapped;
SOCKET SendToSocket = INVALID_SOCKET;
struct sockaddr_in RecvAddr;
struct sockaddr_in LocalAddr;
int RecvAddrSize = sizeof (RecvAddr);
int LocalAddrSize = sizeof (LocalAddr);
u_short Port = 27777;
struct hostent *localHost;
char *ip;
char *targetip;
char *targetport;
char SendBuf[1024] = "Data buffer to send";
int BufLen = 1024;
DWORD BytesSent = 0;
DWORD Flags = 0;
int rc, err;
int retval = 0;
// Validate the parameters
if (argc != 3) {
printf("usage: %s targetip port\n", argv[0]);
printf(" to sendto the localhost on port 27777\n");
printf(" %s 127.0.0.1 27777\n", argv[0]);
return 1;
}
targetip = argv[1];
targetport = argv[2];
//---------------------------------------------
// Initialize Winsock
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rc != 0) {
printf("Unable to load Winsock: %d\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 == WSA_INVALID_EVENT) {
printf("WSACreateEvent failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
//---------------------------------------------
// Create a socket for sending data
SendToSocket =
WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0,
WSA_FLAG_OVERLAPPED);
if (SendToSocket == INVALID_SOCKET) {
printf("socket failed with error: %d\n", WSAGetLastError());
WSACloseEvent(Overlapped.hEvent);
WSACleanup();
return 1;
}
//---------------------------------------------
// Set up the RecvAddr structure with the IP address of
// the receiver (in this example case "123.123.123.1")
// and the specified port number.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_addr.s_addr = inet_addr(targetip);
if (RecvAddr.sin_addr.s_addr == INADDR_NONE) {
printf("The target ip address entered must be a legal IPv4 address\n");
WSACloseEvent(Overlapped.hEvent);
WSACleanup();
return 1;
}
RecvAddr.sin_port = htons( (u_short) atoi(targetport));
if(RecvAddr.sin_port == 0) {
printf("The targetport must be a legal UDP port number\n");
WSACloseEvent(Overlapped.hEvent);
WSACleanup();
return 1;
}
//---------------------------------------------
// Set up the LocalAddr structure with the local IP address
// and the specified port number.
localHost = gethostbyname("");
ip = inet_ntoa(*(struct in_addr *) *localHost->h_addr_list);
LocalAddr.sin_family = AF_INET;
LocalAddr.sin_addr.s_addr = inet_addr(ip);
LocalAddr.sin_port = htons(Port);
//---------------------------------------------
// Bind the sending socket to the LocalAddr structure
// that has the internet address family, local IP address
// and specified port number.
rc = bind(SendToSocket, (struct sockaddr *) &LocalAddr, LocalAddrSize);
if (rc == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
WSACloseEvent(Overlapped.hEvent);
closesocket(SendToSocket);
WSACleanup();
return 1;
}
//---------------------------------------------
// Send a datagram to the receiver
printf("Sending datagram from IPv4 address = %s port=%d\n",
inet_ntoa(LocalAddr.sin_addr), ntohs(LocalAddr.sin_port) );
printf(" to IPv4 address = %s port=%d\n",
inet_ntoa(RecvAddr.sin_addr), ntohs(RecvAddr.sin_port) );
// printf("Sending a datagram...\n");
DataBuf.len = BufLen;
DataBuf.buf = SendBuf;
rc = WSASendTo(SendToSocket, &DataBuf, 1,
&BytesSent, Flags, (SOCKADDR *) & RecvAddr,
RecvAddrSize, &Overlapped, NULL);
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
printf("WSASendTo failed with error: %d\n", err);
WSACloseEvent(Overlapped.hEvent);
closesocket(SendToSocket);
WSACleanup();
return 1;
}
rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED) {
printf("WSAWaitForMultipleEvents failed with error: %d\n",
WSAGetLastError());
retval = 1;
}
rc = WSAGetOverlappedResult(SendToSocket, &Overlapped, &BytesSent,
FALSE, &Flags);
if (rc == FALSE) {
printf("WSASendTo failed with error: %d\n", WSAGetLastError());
retval = 1;
}
else
printf("Number of sent bytes = %d\n", BytesSent);
//---------------------------------------------
// When the application is finished sending, close the socket.
printf("Finished sending. Closing socket.\n");
WSACloseEvent(Overlapped.hEvent);
closesocket(SendToSocket);
printf("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
Requisito | Value |
---|---|
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 |