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 |
---|---|
Se finalizó el circuito virtual debido a un tiempo de espera agotado u otro error. | |
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". | |
El parámetro lpBuffers, lpNumberOfBytesSent, lpOverlapped, lpCompletionRoutine no está totalmente incluido en una parte válida del espacio de direcciones del usuario. | |
Se canceló una llamada de Bloqueo de Windows Socket 1.1 a través de WSACancelBlockingCall. | |
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. | |
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. | |
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. | |
El proveedor de Windows Sockets informa de un interbloqueo de búfer. | |
El socket no está conectado. | |
El descriptor no es un socket. | |
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. | |
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. | |
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, 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.
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.
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.
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 . |
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.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 |