Compartir a través de


Función WSASend (winsock2.h)

La función WSASend envía datos en un socket conectado.

Sintaxis

int WSAAPI WSASend(
  [in]  SOCKET                             s,
  [in]  LPWSABUF                           lpBuffers,
  [in]  DWORD                              dwBufferCount,
  [out] LPDWORD                            lpNumberOfBytesSent,
  [in]  DWORD                              dwFlags,
  [in]  LPWSAOVERLAPPED                    lpOverlapped,
  [in]  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

Parámetros

[in] s

Descriptor que identifica un socket conectado.

[in] lpBuffers

Puntero a una matriz de estructuras WSABUF . Cada estructura WSABUF contiene un puntero a un búfer y la longitud, en bytes, del búfer. En el caso de una aplicación Winsock, una vez que se llama a la función WSASend , 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, en bytes, enviado 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 WSASend . Para obtener más información, vea Uso de dwFlags en la sección Comentarios.

[in] lpOverlapped

Puntero a una estructura WSAOVERLAPPED . Este parámetro se omite 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. Este parámetro 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, WSASend 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
WSAECONNABORTED
Se finalizó el circuito virtual debido a un tiempo de espera agotado u otro error.
WSAECONNRESET
Para un socket de flujo, el circuito virtual se restablece por el lado remoto. La aplicación debería cerrar el socket porque ya no se puede usar. 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".
WSAEFAULT
El parámetro lpBuffers, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine no está totalmente incluido en una parte válida del espacio de direcciones del usuario.
WSAEINTR
Se canceló una llamada de Bloqueo de Windows Socket 1.1 a través de WSACancelBlockingCall.
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.
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
En el caso de un socket de flujo, la conexión se ha interrumpido debido a que la actividad de mantenimiento activo detecta un error mientras la operación estaba en curso. Para un socket de datagrama, este error indica que expiró el tiempo de vida.
WSAENOBUFS
El proveedor de Windows Sockets informa de un interbloqueo de búfer.
WSAENOTCONN
El socket no está conectado.
WSAENOTSOCK
El descriptor no es un socket.
WSAEOPNOTSUPP
MSG_OOB se especificó, pero el socket no es de estilo de flujo, como el tipo SOCK_STREAM, los datos OOB no se admiten en el dominio de comunicación asociado a este socket, MSG_PARTIAL no se admite o el socket es unidireccional y solo admite operaciones de recepción.
WSAESHUTDOWN
El socket se ha apagado; no es posible WSASend en un socket después de que se haya invocado el apagado con el modo establecido 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, la ejecución del comando "SIO_FLUSH" en WSAIoctl o el subproceso que inició la solicitud superpuesta se cerró antes de que se complete la operación. Para obtener más información, vea la sección Comentarios.

Comentarios

La función WSASend proporciona funcionalidad sobre y por encima de la función de envío 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 WSASend se usa para escribir datos salientes de uno o varios búferes en un socket orientado a la conexión especificado por s. Sin embargo, también se puede usar en sockets sin conexión que tengan establecida una dirección del mismo nivel predeterminada estipulada a través de la función connect o WSAConnect .

Un socket creado por la función de socket tendrá el atributo superpuesto como predeterminado. Un socket creado por la función WSASocket con el parámetro dwFlags pasado a WSASocket con el conjunto de bits de WSA_FLAG_OVERLAPPED tendrá el atributo superpuesto. En el caso de los sockets con el atributo superpuesto, WSASend usa E/S superpuesta a menos que los parámetros lpOverlapped y lpCompletionRoutine sean NULL. En ese caso, el socket se trata como un socket no superpuesto. Se producirá una indicación de finalización, invocando la finalización de una rutina o 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.

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 WSASend adopta la misma semántica de bloqueo que el envío. Los datos se copian de los búferes en el búfer del transporte. Si el socket no está bloqueado y orientado a flujos, y no hay suficiente espacio en el búfer del transporte, WSASend devolverá 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, WSASend se bloqueará hasta que se consuma todo el contenido del búfer de la aplicación.

Nota Las opciones de socket SO_RCVTIMEO y SO_SNDTIMEO solo se aplican a los sockets de bloqueo.
 
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 sockets orientados a mensajes, no supere el tamaño máximo del mensaje del proveedor 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.

Windows Me/98/95: La función WSASend no admite más de 16 búferes.

Nota La finalización correcta de un WSASend no indica que los datos se entregaron correctamente.
 

Uso de dwFlags

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 Sockets puede optar por omitir esta marca.
MSG_OOB Envíe datos OOB en un socket de estilo de secuencia, 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 WSASend 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, WSASend 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, WSASend 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. Para obtener más información, vea ExitThread.
 
Se puede llamar a la función WSASend 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 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 siguiente ejemplo de código de C++ es un prototipo de la rutina de finalización.


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. 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 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.

El orden de las llamadas realizadas a WSASend es también el orden en que los búferes se transmiten a la capa de transporte. No se debe llamar a WSASend en el mismo socket orientado a secuencias simultáneamente desde subprocesos diferentes, ya que algunos proveedores de Winsock pueden dividir una solicitud de envío grande en varias transmisiones y esto puede provocar la intercalación de datos no deseados desde varias solicitudes de envío simultáneas en el mismo socket orientado a secuencias.

Código de ejemplo

En el ejemplo de código siguiente se muestra cómo usar la función WSASend en modo de E/S superpuesta.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <Windows.h>

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")

#define DATA_BUFSIZE 4096
#define SEND_COUNT   10

int __cdecl main()
{
    WSADATA wsd;

    struct addrinfo *result = NULL;
    struct addrinfo hints;
    WSAOVERLAPPED SendOverlapped;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET AcceptSocket = INVALID_SOCKET;

    WSABUF DataBuf;
    DWORD SendBytes;
    DWORD Flags;

    char buffer[DATA_BUFSIZE];

    int err = 0;
    int rc, i;

    // Load Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsd);
    if (rc != 0) {
        printf("Unable to load Winsock: %d\n", rc);
        return 1;
    }

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

    // Initialize the hints to obtain the 
    // wildcard bind address for IPv4
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    rc = getaddrinfo(NULL, "27015", &hints, &result);
    if (rc != 0) {
        printf("getaddrinfo failed with error: %d\n", rc);
        return 1;
    }

    ListenSocket = socket(result->ai_family,
                          result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        return 1;
    }

    rc = bind(ListenSocket, result->ai_addr, (int) result->ai_addrlen);
    if (rc == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        return 1;
    }

    rc = listen(ListenSocket, 1);
    if (rc == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        return 1;
    }
    // Accept an incoming connection request
    AcceptSocket = accept(ListenSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET) {
        printf("accept failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        return 1;
    }

    printf("Client Accepted...\n");

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

    // Create an event handle and setup the overlapped structure.
    SendOverlapped.hEvent = WSACreateEvent();
    if (SendOverlapped.hEvent == NULL) {
        printf("WSACreateEvent failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        closesocket(AcceptSocket);
        return 1;
    }

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;

    for (i = 0; i < SEND_COUNT; i++) {

        rc = WSASend(AcceptSocket, &DataBuf, 1,
                     &SendBytes, 0, &SendOverlapped, NULL);
        if ((rc == SOCKET_ERROR) &&
            (WSA_IO_PENDING != (err = WSAGetLastError()))) {
            printf("WSASend failed with error: %d\n", err);
            break;
        }

        rc = WSAWaitForMultipleEvents(1, &SendOverlapped.hEvent, TRUE, INFINITE,
                                      TRUE);
        if (rc == WSA_WAIT_FAILED) {
            printf("WSAWaitForMultipleEvents failed with error: %d\n",
                   WSAGetLastError());
            break;
        }

        rc = WSAGetOverlappedResult(AcceptSocket, &SendOverlapped, &SendBytes,
                                    FALSE, &Flags);
        if (rc == FALSE) {
            printf("WSASend failed with error: %d\n", WSAGetLastError());
            break;
        }

        printf("Wrote %d bytes\n", SendBytes);

        WSAResetEvent(SendOverlapped.hEvent);

    }

    WSACloseEvent(SendOverlapped.hEvent);
    closesocket(AcceptSocket);
    closesocket(ListenSocket);
    freeaddrinfo(result);

    WSACleanup();

    return 0;
}


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

WSABUF

WSACloseEvent

WSAConnect

WSACreateEvent

WSAGetOverlappedResult

WSAOVERLAPPED

WSASocket

WSAWaitForMultipleEvents

Funciones winsock

Referencia de Winsock

connect

enviar

socket