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
WSAEHOSTUNREACH
El host pasado como parámetro nodename no era accesible.
WSAEINVAL
Se pasó un parámetro no válido a la función. El parámetro Reserved debe ser NULL.
WSAENOBUFS
No se pudo asignar memoria suficiente.
WSAENOTSOCK
Se pasó un socket no válido a la función. El parámetro s no debe ser INVALID_SOCKET ni NULL.
WSAETIMEDOUT
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 );

Nota Al emitir una llamada de Winsock de bloqueo como WSAConnectByList con el parámetro de tiempo de espera 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.
 
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.

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

Consulte también

Opciones de socket de IPPROTO_IPV6

SOCKADDR

SOCKET_ADDRESS

SOCKET_ADDRESS_LIST

WSAConnect

WSAConnectByName

WSAGetLastError

getaddrinfo

getpeername

getsockname

setsockopt