Función WSAConnectByList (winsock2.h)
La función WSAConnectByList establece una conexión a una de una colección de posibles puntos de conexión representados por un conjunto de direcciones de destino (nombres de host y puertos). Esta función toma todas las direcciones de destino que se le pasan y todas las direcciones de origen del equipo local e intenta conectarse con todas las combinaciones de direcciones posibles antes de renunciar.
Esta función admite direcciones IPv4 e IPv6.
Sintaxis
BOOL WSAConnectByList(
[in] SOCKET s,
[in] PSOCKET_ADDRESS_LIST SocketAddress,
[in, out] LPDWORD LocalAddressLength,
[out] LPSOCKADDR LocalAddress,
[in, out] LPDWORD RemoteAddressLength,
[out] LPSOCKADDR RemoteAddress,
[in] const timeval *timeout,
[in] LPWSAOVERLAPPED Reserved
);
Parámetros
[in] s
Descriptor que identifica un socket independiente y no conectado. Tenga en cuenta que, a diferencia de otras llamadas de Winsock para establecer una conexión (por ejemplo, WSAConnect), la función WSAConnectByList requiere un socket independiente.
[in] SocketAddress
Puntero a una estructura de SOCKET_ADDRESS_LIST que representa los posibles pares de puerto y dirección de destino para conectarse a un mismo nivel. Es responsabilidad de la aplicación rellenar el número de puerto en cada estructura de SOCKET_ADDRESS del SOCKET_ADDRESS_LIST.
[in, out] LocalAddressLength
En la entrada, un puntero al tamaño, en bytes, del búfer LocalAddress proporcionado por el autor de la llamada. En la salida, un puntero al tamaño, en bytes, del SOCKADDR para la dirección local almacenada en el búfer LocalAddress rellenado por el sistema tras completar correctamente la llamada.
[out] LocalAddress
Puntero a la estructura SOCKADDR que recibe la dirección local de la conexión. El tamaño del parámetro es exactamente el tamaño devuelto en LocalAddressLength. Esta es la misma información que devolvería la función getsockname . Este parámetro puede ser NULL, en cuyo caso, se omite el parámetro LocalAddressLength .
[in, out] RemoteAddressLength
En la entrada, un puntero al tamaño, en bytes, del búfer RemoteAddress proporcionado por el autor de la llamada. En la salida, un puntero al tamaño, en bytes, del SOCKADDR para la dirección remota almacenada en el búfer remoteAddress rellenado por el sistema tras completar correctamente la llamada.
[out] RemoteAddress
Puntero a la estructura SOCKADDR que recibe la dirección remota de la conexión. Esta es la misma información que devolvería la función getpeername . Este parámetro puede ser NULL, en cuyo caso se omite RemoteAddressLength .
[in] timeout
El tiempo, en milisegundos, para esperar una respuesta de la aplicación remota antes de anular la llamada. Este parámetro puede ser NULL en cuyo caso WSAConnectByList se completará después de establecer correctamente la conexión o después de que se intentó realizar una conexión y se produjo un error en todos los posibles pares de direcciones remotas locales.
[in] Reserved
Reservado para la implementación futura. Este parámetro debe establecerse en NULL.
Valor devuelto
Si se establece una conexión, WSAConnectByList devuelve los parámetros TRUE y LocalAddress y RemoteAddress se rellenan si el autor de la llamada proporcionó estos búferes.
Si se produce un error en la llamada, se devuelve FALSE . A continuación, se puede llamar a WSAGetLastError para obtener información de error extendida.
Código devuelto | Descripción |
---|---|
|
El host pasado como parámetro nodename no era accesible. |
|
Se pasó un parámetro no válido a la función. El parámetro Reserved debe ser NULL. |
|
No se pudo asignar memoria suficiente. |
|
Se pasó un socket no válido a la función. El parámetro s no debe ser INVALID_SOCKET ni NULL. |
|
No se recibió una respuesta de la aplicación remota antes de que se superara el parámetro de tiempo de espera . |
Comentarios
WSAConnectByList es similar a la función WSAConnectByName . En lugar de tomar un único nombre de host y nombre de servicio (puerto), WSAConnectByList toma una lista de direcciones (direcciones y puertos de host) y se conecta a una de las direcciones. La función WSAConnectByList está diseñada para admitir escenarios de colaboración punto a punto en los que una aplicación necesita conectarse a cualquier nodo disponible de una lista de posibles nodos. WSAConnectByList es compatible con las versiones IPv6 e IPv4.
El autor de la llamada proporciona el conjunto de posibles destinos, representado por una lista de direcciones. WSAConnectByList hace más que simplemente intentar conectarse a una de las posibles muchas direcciones de destino. En concreto, la función toma todas las direcciones remotas pasadas por el autor de la llamada, todas las direcciones locales y, a continuación, intenta primero una conexión mediante pares de direcciones con la mayor probabilidad de éxito. Por lo tanto, WSAConnectByList no solo garantiza que se establezca la conexión si una conexión es posible, sino que también minimiza el tiempo para establecer la conexión.
El autor de la llamada puede especificar los búferes y las longitudes de LocalAddress y RemoteAddress para determinar las direcciones locales y remotas para las que la conexión se estableció correctamente.
El parámetro timeout permite al autor de la llamada limitar el tiempo empleado por la función en establecer una conexión. Internamente, WSAConnectByList realiza varias operaciones (intentos de conexión). Entre cada operación, se comprueba el parámetro de tiempo de espera para ver si se ha superado el tiempo de espera y, si es así, se anula la llamada. Tenga en cuenta que una operación individual (connect) no se interrumpirá una vez que se supere el tiempo de espera , por lo que la llamada WSAConnectByList puede tardar más tiempo en agotarse el tiempo de espera que el valor especificado en el parámetro timeout .
WSAConnectByList tiene limitaciones: solo funciona para sockets orientados a la conexión, como los de tipo SOCK_STREAM. La función no admite la E/S superpuesta o el comportamiento de no bloqueo. WSAConnectByList se bloqueará incluso si el socket está en modo de no bloqueo. WSAConnectByList intentará conectarse (uno a uno) a las distintas direcciones proporcionadas por el autor de la llamada. Potencialmente, cada uno de estos intentos de conexión puede producir un error con un código de error diferente. Puesto que solo se puede devolver un código de error único, el valor devuelto es el código de error del último intento de conexión.
Para permitir que las direcciones IPv6 e IPv4 se pasen en la lista de direcciones única aceptada por la función, se deben realizar los pasos siguientes antes de llamar a la función:
- Se debe llamar a la función setsockopt en un socket creado para la familia de direcciones AF_INET6 para deshabilitar la opción de socket IPV6_V6ONLY antes de llamar a WSAConnectByList. Esto se logra mediante una llamada a la función setsockopt en el socket con el parámetro level establecido en IPPROTO_IPV6 (vea IPPROTO_IPV6 Opciones de socket), el parámetro optname establecido en IPV6_V6ONLY y el valor del parámetro optvalue establecido en cero .
- Las direcciones IPv4 deben representarse en el formato de dirección IPv4 asignada a IPv4, lo que permite que una aplicación solo IPv6 se comunique con un nodo IPv4. El formato de dirección IPv4 asignado a IPv6 permite representar la dirección IPv4 de un nodo IPv4 como una dirección IPv6. La dirección IPv4 se codifica en los 32 bits de orden bajo de la dirección IPv6 y los 96 bits de orden superior contienen el prefijo fijo 0:0:0:0:0:0:0:FFFF. El formato de dirección IPv4 asignado a IPv6 se especifica en RFC 4291. Para obtener más información, vea www.ietf.org/rfc/rfc4291.txt. La macro IN6ADDR_SETV4MAPPED en Mstcpip.h se puede usar para convertir una dirección IPv4 al formato de dirección IPv6 asignado a IPv4 necesario.
Las matrices de punteros pasados en el parámetro SocketAddressList apuntan a una matriz de estructuras SOCKET_ADDRESS , que son un tipo de datos genérico. Los parámetros RemoteAddress y LocalAddress también apuntan a estructuras SOCKADDR . Cuando se llama a WSAConnectByList , se espera que un tipo de dirección de socket específico del protocolo de red o la familia de direcciones que se use realmente se pasen en estos parámetros. Por lo tanto, para las direcciones IPv4, un puntero a una estructura de sockaddr_in se convertiría a un puntero a SOCKADDR cuando se pasa como parámetro. En el caso de las direcciones IPv6, un puntero a una estructura de sockaddr_in6 se convierte en un puntero a SOCKADDR cuando se pasa como parámetro. El parámetro SocketAddressList puede contener punteros a una combinación de direcciones IPv4 e IPv6. Por lo tanto, algunos punteros SOCKET_ADDRESS pueden ser para sockaddr_in estructuras y otros pueden ser para sockaddr_in6 estructuras. Si se espera que se puedan usar direcciones IPv6, los parámetros RemoteAddress y LocalAddress deben apuntar a sockaddr_in6 estructuras y convertirse en estructuras SOCKADDR . Los parámetros RemoteAddressLength y LocalAddressLength deben representar la longitud de estas estructuras más grandes.
Cuando la función WSAConnectByList devuelve TRUE, el socket s está en el estado predeterminado de un socket conectado. El socket s no habilita las propiedades o opciones establecidas previamente hasta que SO_UPDATE_CONNECT_CONTEXT se establece en el socket. Use la función setsockopt para establecer la opción SO_UPDATE_CONNECT_CONTEXT.
Por ejemplo:
//Need to #include <mswsock.h> for SO_UPDATE_CONNECT_CONTEXT
int iResult = 0;
iResult = setsockopt( s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0 );
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.
Ejemplos
Establezca una conexión mediante WSAConnectByList.
#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
SOCKET
OpenAndConnect(SOCKET_ADDRESS_LIST *AddressList)
{
SOCKET ConnSocket = INVALID_SOCKET;
int ipv6only = 0;
int iResult;
BOOL bSuccess;
SOCKADDR_STORAGE LocalAddr = {0};
SOCKADDR_STORAGE RemoteAddr = {0};
DWORD dwLocalAddr = sizeof(LocalAddr);
DWORD dwRemoteAddr = sizeof(RemoteAddr);
ConnSocket = socket(AF_INET6, SOCK_STREAM, 0);
if (ConnSocket == INVALID_SOCKET){
return INVALID_SOCKET;
}
iResult = setsockopt(ConnSocket, IPPROTO_IPV6,
IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
if (iResult == SOCKET_ERROR){
closesocket(ConnSocket);
return INVALID_SOCKET;
}
// AddressList may contain IPv6 and/or IPv4Mapped addresses
bSuccess = WSAConnectByList(ConnSocket,
AddressList,
&dwLocalAddr,
(SOCKADDR*)&LocalAddr,
&dwRemoteAddr,
(SOCKADDR*)&RemoteAddr,
NULL,
NULL);
if (bSuccess){
return ConnSocket;
} else {
return INVALID_SOCKET;
}
}
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 |