Функция WSAConnectByList (winsock2.h)

Функция WSAConnectByList устанавливает подключение к одной из коллекции возможных конечных точек, представленных набором целевых адресов (имена узлов и портов). Эта функция принимает все адреса назначения, переданные ей, и все исходные адреса локального компьютера, и пытается подключиться, используя все возможные сочетания адресов, прежде чем отказаться.

Эта функция поддерживает адреса IPv4 и IPv6.

Синтаксис

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
);

Параметры

[in] s

Дескриптор, определяющий несвязанный и несвязанный сокет. Обратите внимание, что в отличие от других вызовов Winsock для установки соединения (например, WSAConnect), для функции WSAConnectByList требуется незавязанный сокет.

[in] SocketAddress

Указатель на структуру SOCKET_ADDRESS_LIST , представляющую возможные пары адреса назначения и портов для подключения к одноранговой точке. За заполнение номера порта в каждой структуре SOCKET_ADDRESS в SOCKET_ADDRESS_LIST отвечает приложение.

[in, out] LocalAddressLength

На входных данных — указатель на размер буфера LocalAddress в байтах , предоставленного вызывающим объектом. В выходных данных — указатель на размер (в байтах) SOCKADDR для локального адреса, хранящегося в буфере LocalAddress , заполненном системой после успешного завершения вызова.

[out] LocalAddress

Указатель на структуру SOCKADDR , которая получает локальный адрес подключения. Размер параметра точно совпадает с размером, возвращенным в LocalAddressLength. Это те же сведения, которые будут возвращены функцией getsockname . Этот параметр может иметь значение NULL. В этом случае параметр LocalAddressLength игнорируется.

[in, out] RemoteAddressLength

На входных данных — указатель на размер буфера RemoteAddress в байтах , предоставленного вызывающим объектом. На выходе — указатель на размер (в байтах) SOCKADDR для удаленного адреса, хранящегося в буфере RemoteAddress , заполненного системой после успешного завершения вызова.

[out] RemoteAddress

Указатель на структуру SOCKADDR , которая получает удаленный адрес подключения. Это те же сведения, которые будут возвращены функцией getpeername . Этот параметр может иметь значение NULL. В этом случае RemoteAddressLength игнорируется.

[in] timeout

Время (в миллисекундах) ожидания ответа от удаленного приложения перед прерыванием вызова. Этот параметр может иметь значение NULL , и в этом случае WSAConnectByList завершится после успешного установления подключения или после попытки подключения и сбоя для всех возможных пар "локальный—удаленный адрес".

[in] Reserved

Зарезервировано для будущей реализации. Этот параметр должен иметь значение NULL.

Возвращаемое значение

Если подключение установлено, WSAConnectByList возвращает значение TRUE , а параметры LocalAddress и RemoteAddress заполняются, если эти буферы были предоставлены вызывающим объектом.

Если вызов завершается сбоем, возвращается значение FALSE . Затем можно вызвать WSAGetLastError для получения расширенных сведений об ошибке.

Код возврата Описание
WSAEHOSTUNREACH
Узел, переданный в качестве параметра nodename , был недостижим.
WSAEINVAL
В функцию передан недопустимый параметр. Параметр Reserved должен иметь значение NULL.
WSAENOBUFS
Не удалось выделить достаточный объем памяти.
WSAENOTSOCK
В функцию передан недопустимый сокет. Параметр s не должен быть INVALID_SOCKET или NULL.
WSAETIMEDOUT
Ответ от удаленного приложения не был получен до превышения времени ожидания .

Комментарии

WSAConnectByList похож на функцию WSAConnectByName . Вместо одного имени узла и имени службы (порта) WSAConnectByList принимает список адресов (адресов узлов и портов) и подключается к одному из адресов. Функция WSAConnectByList предназначена для поддержки сценариев одноранговой совместной работы, в которых приложению необходимо подключиться к любому доступному узлу из списка потенциальных узлов. WSAConnectByList совместим с версиями IPv6 и IPv4.

Набор возможных назначений, представленный списком адресов, предоставляется вызывающим. WSAConnectByList не просто пытается подключиться к одному из возможных целевых адресов. В частности, функция принимает все удаленные адреса, переданные вызывающим абонентом, все локальные адреса, а затем пытается установить соединение с использованием пар адресов с наибольшей вероятностью успеха. Таким образом, WSAConnectByList не только гарантирует, что подключение будет установлено, если подключение возможно, но и сокращает время установки соединения.

Вызывающий объект может указать буферы и длину LocalAddress и RemoteAddress , чтобы определить локальные и удаленные адреса, для которых подключение было успешно установлено.

Параметр timeout позволяет вызывающей объекту ограничить время, затраченное функцией на установление соединения. На внутреннем сервере WSAConnectByList выполняет несколько операций (попытки подключения). В период между каждой операцией проверяется параметр времени ожидания , чтобы узнать, превышено ли время ожидания , и, если да, вызов прерывается. Обратите внимание, что отдельная операция (подключение) не прерывается после превышения времени ожидания , поэтому время ожидания вызова WSAConnectByList может занять больше времени ожидания, чем значение, указанное в параметре timeout .

WSAConnectByList имеет ограничения: он работает только для сокетов, ориентированных на подключение, таких как сокеты типа SOCK_STREAM. Функция не поддерживает перекрывающееся или неблокирующее поведение. WSAConnectByList будет блокироваться, даже если сокет находится в неблокирующем режиме. WSAConnectByList попытается подключиться (по одному) к различным адресам, предоставленным вызывающим абонентом. Возможно, каждая из этих попыток подключения может завершиться ошибкой с другим кодом ошибки. Так как может быть возвращен только один код ошибки, возвращенным значением является код ошибки из последней попытки подключения.

Чтобы разрешить передавать адреса IPv6 и IPv4 в одном списке адресов, принятом функцией, перед вызовом функции необходимо выполнить следующие действия:

  • Функция setsockopt должна вызываться в сокете, созданном для семейства адресов AF_INET6, чтобы отключить параметр сокета IPV6_V6ONLY перед вызовом WSAConnectByList. Это достигается путем вызова функции setsockopt в сокете с параметром уровня , равным IPPROTO_IPV6 (см . IPPROTO_IPV6 Параметры сокета), параметру optname присвоено значение IPV6_V6ONLY, а значение параметра optvalue равно нулю.
  • Все IPv4-адреса должны быть представлены в формате IPv6-адресов, сопоставленных с IPv4, что позволяет приложению только IPv6 взаимодействовать с узлом IPv4. Формат IPv6-адресов, сопоставленный с IPv4, позволяет представлять IPv4-адрес узла IPv4 в виде IPv6-адреса. IPv4-адрес закодирован в 32 бита IPv6-адреса низкого порядка, а 96-разрядные устройства высокого порядка содержат фиксированный префикс 0:0:0:0:0:0:FFFF. Формат IPv6-адресов, сопоставленный с IPv4, указан в RFC 4291. Дополнительные сведения см. в разделе www.ietf.org/rfc/rfc4291.txt. Макрос IN6ADDR_SETV4MAPPED в Mstcpip.h можно использовать для преобразования IPv4-адреса в требуемый формат IPv6-адресов.

Массивы указателей, передаваемые в параметре SocketAddressList , указывают на массив SOCKET_ADDRESS структур, которые являются универсальным типом данных. Параметры RemoteAddress и LocalAddress также указывают на структуры SOCKADDR . При вызове WSAConnectByList ожидается, что в этих параметрах будет передаваться тип адреса сокета, относящегося к используемому сетевому протоколу или семейству адресов. Таким образом, для IPv4-адресов указатель на структуру sockaddr_in будет приведен к указателю на SOCKADDR при передаче в качестве параметра. Для IPv6-адресов указатель на структуру sockaddr_in6 будет приведен к указателю на SOCKADDR при передаче в качестве параметра. Параметр SocketAddressList может содержать указатели на сочетание адресов IPv4 и IPv6. Таким образом, некоторые SOCKET_ADDRESS указатели могут быть sockaddr_in структуры, а другие могут быть sockaddr_in6 структуры. Если предполагается, что можно использовать IPv6-адреса, то параметры RemoteAddress и LocalAddress должны указывать на sockaddr_in6 структуры и приводиться к структурам SOCKADDR . Параметры RemoteAddressLength и LocalAddressLength должны представлять длину этих больших структур.

Когда функция WSAConnectByList возвращает значение TRUE, сокеты будут в состоянии по умолчанию для подключенного сокета. Сокет не включает ранее заданные свойства или параметры до тех пор, пока в сокете не будет задано SO_UPDATE_CONNECT_CONTEXT. Используйте функцию setsockopt , чтобы задать параметр SO_UPDATE_CONNECT_CONTEXT.

Пример:

//Need to #include <mswsock.h> for SO_UPDATE_CONNECT_CONTEXT

int iResult = 0;

iResult = setsockopt( s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0 );

Примечание При выполнении блокирующего вызова Winsock, например WSAConnectByList , с параметром timeout , равным NULL, Winsock может потребоваться дождаться сетевого события, прежде чем вызов сможет завершиться. В этой ситуации Winsock выполняет оповещенное ожидание, которое может быть прервано асинхронным вызовом процедуры (APC), запланированным в том же потоке. Выполнение другого блокирующего вызова Winsock внутри APC, который прервал текущий блокирующий вызов Winsock в том же потоке, приведет к неопределенному поведению, и клиенты Winsock никогда не должны пытаться его выполнять.
 
Windows Phone 8. Эта функция поддерживается для приложений Магазина Windows Phone на Windows Phone 8 и более поздних версиях.

Windows 8.1 и Windows Server 2012 R2: эта функция поддерживается для приложений Магазина Windows на Windows 8.1, Windows Server 2012 R2 и более поздних версий.

Примеры

Установите подключение с помощью 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;
    }
}

Требования

   
Минимальная версия клиента Windows 8.1, Windows Vista [классические приложения | Приложения UWP]
Минимальная версия сервера Windows Server 2003 [классические приложения | Приложения UWP]
Целевая платформа Windows
Header winsock2.h
Библиотека Ws2_32.lib
DLL Ws2_32.dll

См. также раздел

Параметры сокета IPPROTO_IPV6

SOCKADDR

SOCKET_ADDRESS

SOCKET_ADDRESS_LIST

WSAConnect

WSAConnectByName

WSAGetLastError

getaddrinfo

getpeername

getsockname

setsockopt