私は IPv6 ソケット、特に Windows Vista 以降で提供される「デュアル スタック」機能、および明らかにデフォルトで Unix で提供される機能を試しています。サーバーを特定の IP アドレスまたはローカル マシンのホスト名解決にバインドすると、IPv4 クライアントからの接続を受け入れることができないことがわかりました。ただし、INADDR_ANY にバインドすると、できます。
私のサーバーの次のコードを検討してください。IPv6 ソケットを作成し、IPV6_V6ONLY フラグをゼロに設定するという Microsoft のアドバイスに従っていることがわかります。
addrinfo* result, *pCurrent, hints;
memset(&hints, 0, sizeof hints); // Must do this!
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // We intend to use the addrinfo in a call to connect(). (I know it is ignored if we specify a server to connect to...)
int nRet = getaddrinfo("powerhouse", "82", &hints, &result);
SOCKET sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
int no = 0;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) != 0)
return -1;
if (bind(sock, result->ai_addr, result->ai_addrlen) == SOCKET_ERROR)
return -1;
if (listen(sock, SOMAXCONN) == SOCKET_ERROR)
return -1;
SOCKET sockClient = accept(sock, NULL, NULL);
これが私のクライアントのコードです。IPv4 ソケットを作成し、サーバーに接続しようとしていることがわかります。
addrinfo* result, *pCurrent, hints;
memset(&hints, 0, sizeof hints); // Must do this!
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo("powerhouse", "82", &hints, &result) != 0)
return -1;
SOCKET sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
int nRet = connect(sock, result->ai_addr, result->ai_addrlen);
私の接続呼び出しの結果は常に 10061 です: 接続が拒否されました。
サーバー コードを :: にバインドするように変更し (または NULL ホストを getaddrinfo() に渡す (同じこと))、クライアント コードを変更して getaddrinfo() 呼び出しで NULL ホストを指定すると、V4 クライアントは接続できます。大丈夫。
誰でも理由を説明できますか?デュアルソケットの動作が必要な場合は、NULL ホストを指定する必要がある (したがって、INADDR_ANY を使用する) 必要があるということは何も読んでいません。マルチホーム ホストがあり、使用可能な IP の一部でのみ IPv4 を受け入れたいので、これは必須ではありません。
編集 15/05/2013:
これは、コードが失敗する理由について私を混乱させた関連ドキュメントです。
IPv6 Winsock アプリケーション用のデュアルスタック ソケットから
「Windows Vista 以降では、IPv6 と IPv4 の両方のトラフィックを処理できる単一の IPv6 ソケットを作成する機能が提供されています。たとえば、IPv6 用の TCP リッスン ソケットが作成され、デュアル スタック モードになり、ポート 5001 にバインドされます。このデュアルスタック ソケットは、ポート 5001 に接続する IPv6 TCP クライアントからの接続と、ポート 5001 に接続する IPv4 TCP クライアントからの接続を受け入れることができます。」
「デフォルトでは、Windows Vista 以降で作成された IPv6 ソケットは、IPv6 プロトコルでのみ動作します。IPv6 ソケットをデュアルスタック ソケットにするためには、setsockopt 関数を IPV6_V6ONLY ソケット オプションで呼び出して、この値を次のように設定する必要があります。 IPV6_V6ONLY ソケット オプションがゼロに設定されている場合、AF_INET6 アドレス ファミリ用に作成されたソケットを使用して、IPv6 アドレスまたは IPv4 マップ アドレスとの間でパケットを送受信できます(強調鉱山)」