WSAConnectByList 関数 (winsock2.h)

WSAConnectByList 関数は、一連の宛先アドレス (ホスト名とポート) で表される可能性のあるエンドポイントのコレクションのうち 1 つに接続を確立します。 この関数は、渡されたすべての宛先アドレスとローカル コンピューターのすべてのソース アドレスを受け取り、可能なすべてのアドレスの組み合わせを使用して接続を試行してから、あきらめます。

この関数は、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_LISTの各 SOCKET_ADDRESS 構造体にポート 番号を入力する必要があります。

[in, out] LocalAddressLength

入力時に、呼び出し元によって提供される LocalAddress バッファーのサイズ (バイト単位) へのポインター。 出力時に、呼び出しが正常に完了したときにシステムによって入力された LocalAddress バッファーに格納されているローカル アドレスの SOCKADDR のサイズ (バイト単位) へのポインター。

[out] LocalAddress

接続のローカル アドレスを受け取る SOCKADDR 構造体へのポインター。 パラメーターのサイズは、 LocalAddressLength で返されるサイズとまったく同じになります。 これは、 getsockname 関数によって返されるのと同じ情報です。 このパラメーターには NULL を指定できます。この場合、 LocalAddressLength パラメーターは無視されます。

[in, out] RemoteAddressLength

入力時に、呼び出し元によって提供される RemoteAddress バッファーのサイズ (バイト単位) へのポインター。 出力時に、呼び出しが正常に完了したときにシステムによって埋め込まれた RemoteAddress バッファーに格納されているリモート アドレスの SOCKADDR のサイズ (バイト単位) へのポインター。

[out] RemoteAddress

接続のリモート アドレスを受け取る SOCKADDR 構造体へのポインター。 これは、 getpeername 関数によって返されるのと同じ情報です。 このパラメーターには NULL を指定できます。この場合、 RemoteAddressLength は無視されます。

[in] timeout

呼び出しを中止する前にリモート アプリケーションからの応答を待機する時間 (ミリ秒単位)。 このパラメーターには NULL を 指定できます。この場合、 WSAConnectByList は、接続が正常に確立された後、または接続が試行され、考えられるすべてのローカル とリモート のアドレス ペアで失敗した後に完了します。

[in] Reserved

今後の実装用に予約されています。 このパラメーターは NULL に設定する必要があります。

戻り値

接続が確立されている場合、 WSAConnectByListTRUE を 返し、これらのバッファーが呼び出し元によって提供された場合、 LocalAddress パラメーターと RemoteAddress パラメーターが入力されます。

呼び出しが失敗した場合は、 FALSE が返されます。 WSAGetLastError を呼び出して、拡張エラー情報を取得できます。

リターン コード 説明
WSAEHOSTUNREACH
nodename パラメーターとして渡されたホストに到達できませんでした。
WSAEINVAL
無効なパラメーターが関数に渡されました。 予約済みパラメーターは NULL である必要があります。
WSAENOBUFS
十分なメモリを割り当てませんでした。
WSAENOTSOCK
無効なソケットが関数に渡されました。 s パラメーターは、INVALID_SOCKETまたは NULL にすることはできません。
WSAETIMEDOUT
タイムアウト パラメーターを超える前に、リモート アプリケーションからの応答を受信できませんでした。

解説

WSAConnectByListWSAConnectByName 関数に似ています。 WSAConnectByList は、単一のホスト名とサービス名 (ポート) を取得する代わりに、アドレス (ホスト アドレスとポート) の一覧を取得し、いずれかのアドレスに接続します。 WSAConnectByList 関数は、アプリケーションが潜在的なノードの一覧から使用可能なノードに接続する必要があるピア ツー ピア コラボレーション シナリオをサポートするように設計されています。 WSAConnectByList は、IPv6 と IPv4 の両方のバージョンと互換性があります。

アドレスのリストで表される一連の可能な宛先は、呼び出し元によって提供されます。 WSAConnectByList は、単に多くの宛先アドレスのいずれかに接続を試みるだけではありません。 具体的には、関数は呼び出し元によって渡されたすべてのリモート アドレス、すべてのローカル アドレスを受け取り、成功の可能性が最も高いアドレス ペアを使用して最初に接続を試みます。 そのため、 WSAConnectByList では、接続が可能であれば接続が確立されるだけでなく、接続を確立する時間も最小限に抑えられます。

呼び出し元は 、LocalAddress バッファーと RemoteAddress バッファーと長さを指定して、接続が正常に確立されたローカル アドレスとリモート アドレスを決定できます。

timeout パラメーターを使用すると、呼び出し元は、接続の確立に関数が費やす時間を制限できます。 WSAConnectByList は内部的に複数の操作 (接続試行) を実行します。 各操作の間に、 タイムアウト パラメーターがチェックされ、 タイムアウト を超えたかどうかが確認され、タイムアウトが発生した場合は呼び出しが中止されます。 タイムアウトを超えると個々の操作 (接続) が中断されないため、WSAConnectByList 呼び出しがタイムアウトパラメーターで指定された値よりもタイムアウトするまでに時間がかかる場合があることに注意してください。

WSAConnectByList には制限があります。これは、SOCK_STREAM型のソケットなど、接続指向のソケットに対してのみ機能します。 関数は、重複した I/O または非ブロッキング動作をサポートしていません。 ソケットが非ブロッキング モードの場合でも、WSAConnectByList はブロックします。 WSAConnectByList は、呼び出し元によって提供されるさまざまなアドレスに (1 つずつ) 接続しようとします。 これらの各接続試行が、異なるエラー コードで失敗する可能性があります。 返すことができるエラー コードは 1 つだけであるため、返される値は最後の接続試行のエラー コードです。

IPv6 アドレスと IPv4 アドレスの両方を、関数で受け入れられる単一アドレス一覧で渡せるようにするには、関数を呼び出す前に次の手順を実行する必要があります。

  • WSAConnectByList を呼び出す前に、IPV6_V6ONLY ソケット オプションを無効にするには、AF_INET6 アドレス ファミリ用に作成されたソケットで setsockopt 関数を呼び出す必要があります。 これは、レベル パラメーターを IPPROTO_IPV6 に設定し (IPPROTO_IPV6 ソケット オプションを参照)、optname パラメーターを IPV6_V6ONLY に設定し、optvalue パラメーター値を 0 に設定して、ソケットで setsockopt 関数を呼び出すことによって実現されます。
  • IPv4 アドレスは、IPv4 マップ IPv6 アドレス形式で表す必要があります。これにより、IPv6 のみのアプリケーションが IPv4 ノードと通信できるようになります。 IPv4 マップの IPv6 アドレス形式を使用すると、IPv4 ノードの IPv4 アドレスを IPv6 アドレスとして表すことができます。 IPv4 アドレスは IPv6 アドレスの下位 32 ビットにエンコードされ、上位 96 ビットは固定プレフィックス 0:0:0:0:0:0:FFFF を保持します。 IPv4 マップ IPv6 アドレス形式は RFC 4291 で指定されています。 詳細については、「 www.ietf.org/rfc/rfc4291.txt」を参照してください。 Mstcpip.h のIN6ADDR_SETV4MAPPED マクロを使用して、IPv4 アドレスを必要な 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 を返すと、ソケット s は接続されているソケットの既定の状態になります。 ソケット s では、ソケットで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 );

メモタイムアウト パラメーターが NULL に設定された WSAConnectByList などのブロッキング Winsock 呼び出しを発行する場合、Winsock は呼び出しを完了する前にネットワーク イベントを待機する必要がある場合があります。 Winsock は、この状況でアラート可能な待機を実行します。この待機は、同じスレッドでスケジュールされた非同期プロシージャ 呼び出し (APC) によって中断される可能性があります。 同じスレッドで進行中の Winsock 呼び出しを中断した APC 内で別のブロック Winsock 呼び出しを発行すると、未定義の動作が発生し、Winsock クライアントが試行してはなりません。
 
Windows Phone 8: この関数は、Windows Phone 8 以降の Windows Phone ストア アプリでサポートされています。

Windows 8.1Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストア アプリでサポートされています。

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
ヘッダー winsock2.h
Library Ws2_32.lib
[DLL] Ws2_32.dll

関連項目

IPPROTO_IPV6 ソケット オプション

Sockaddr

SOCKET_ADDRESS

SOCKET_ADDRESS_LIST

WSAConnect

WSAConnectByName

WSAGetLastError

getaddrinfo

getpeername

getsockname

setsockopt