Compartir a través de


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
WSAEACCES
La dirección solicitada es una dirección de difusión, pero no se ha establecido la marca adecuada.
WSAEADDRNOTAVAIL
La dirección remota no es una dirección válida (como ADDR_ANY).
WSAEAFNOSUPPORT
Las direcciones de la familia especificada no se pueden usar con este socket.
WSAECONNRESET
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".
WSAEDESTADDRREQ
Se requiere una dirección de destino.
WSAEFAULT
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.
WSAEHOSTUNREACH
Se intentó realizar una operación de socket a un host inalcanzable.
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 con el enlace o el socket no se crea con la marca superpuesta.
WSAEMSGSIZE
El socket está orientado a mensajes y el mensaje es mayor que el máximo admitido por el transporte subyacente.
WSAENETDOWN
Error en el subsistema de red.
WSAENETRESET
Para un socket de datagrama, este error indica que expiró el tiempo de vida.
WSAENETUNREACH
La red no se puede alcanzar desde este host en estos momentos.
WSAENOBUFS
El proveedor de Windows Sockets informa de un interbloqueo de búfer.
WSAENOTCONN
El socket no está conectado (solo sockets orientados a la conexión).
WSAENOTSOCK
El descriptor no es un socket.
WSAESHUTDOWN
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.
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 envío 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á en un momento posterior.
WSA_OPERATION_ABORTED
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.
La función WSASendTo se usa normalmente en un socket sin conexión especificado por s para enviar un datagrama contenido en uno o varios búferes a un socket del mismo nivel específico identificado por el parámetro lpTo . Incluso si el socket sin conexión se ha conectado previamente mediante la función connect a una dirección específica, lpTo invalida la dirección de destino solo para ese datagrama determinado. En un socket orientado a la conexión, se omiten los parámetros lpTo e iToLen ; en este caso, WSASendTo es equivalente a WSASend.

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.

Nota Si se abre un socket, se realiza una llamada a setsockopt y, a continuación, se realiza una llamada sendto , Windows Sockets realiza una llamada de función de enlace implícita.
 
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, 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 .
 
Nota Al emitir una llamada winsock de bloqueo como WSASendTo 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, 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.
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 está cerrado antes de que se completen las operaciones. Consulte ExitThread para obtener más información.
 
Se puede llamar a la función WSASendTo mediante E/S superpuesta desde dentro de la rutina de finalización de una función WSARecv, WSARecvFrom, WSASend o WSASendTo anterior. 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 .

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

Consulte también

WSACloseEvent

WSACreateEvent

WSAGetOverlappedResult

WSASocket

WSAWaitForMultipleEvents

Funciones winsock

Referencia de Winsock