Podłączanie klienta IPv4 do serwera IPv6: odrzucono połączenie

Eksperymentuję z gniazdami IPv6, w szczególności z „podwójnym stosem” oferowanym w Windows Vista i nowszych wersjach, a domyślnie w Uniksie. Stwierdzam, że kiedy wiążę serwer z określonym adresem IP lub z rozdzielczością nazwy hosta na moim komputerze lokalnym, nie mogę zaakceptować połączenia od klienta IPv4. Kiedy jednak łączę się z INADDR_ANY, mogę to zrobić.

Proszę wziąć pod uwagę następujący kod dla mojego serwera. Widać, że postępuję zgodnie z zaleceniami Microsoftu dotyczącymi tworzenia gniazda IPv6, a następnie ustawiania flagi IPV6_V6ONLY na zero:

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

Oto kod dla mojego klienta. Widać, że tworzę gniazdo IPv4 i próbuję połączyć się z moim serwerem:

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

Wynik mojego połączenia jest zawsze 10061: połączenie odrzucone.

Jeśli zmienię kod serwera, aby powiązać z :: (lub przekazać host NULL do getaddrinfo () (to samo)), i zmienić kod mojego klienta, aby określić host NULL w wywołaniu getaddrinfo (), to klient V4 może się połączyć w porządku.

Czy ktoś może wyjaśnić, dlaczego proszę? Nie przeczytałem niczego, co musimy określić jako host NULL (stąd użyj INADDR_ANY), jeśli chcemy zachowania dual-socket. Nie może to być wymogiem, ponieważ to, co mam hosta wieloadresowego i chcę zaakceptować IPv4 tylko na niektórych dostępnych IP?

EDYTUJ 15/05/2013:

Jest to odpowiednia dokumentacja, która sprawiła, że ​​pomyliłem się, dlaczego mój kod nie działa:

ZGniazda Dual-Stack dla aplikacji Winsock IPv6

„System Windows Vista i nowsze oferują możliwość utworzenia pojedynczego gniazda IPv6, które obsługuje zarówno ruch IPv6, jak i IPv4. Na przykład tworzone jest gniazdo nasłuchiwania TCP dla IPv6, przełączane w tryb podwójnego stosu i powiązane z portem 5001. Ten podwójny gniazdo stosu może akceptować połączenia od klientów TCP IPv6 łączących się z portem 5001 iz klientów TCP IPv4 łączących się z portem 5001. "

„Domyślnie gniazdo IPv6 utworzone w systemie Windows Vista i nowszym działa tylko za pośrednictwem protokołu IPv6. Aby gniazdo IPv6 stało się gniazdem z dwoma stosami, należy wywołać funkcję setsockopt za pomocą opcji gniazda IPV6_V6ONLY, aby ustawić tę wartość na zero, zanim gniazdo zostanie powiązane z adresem IP.Gdy opcja gniazda IPV6_V6ONLY jest ustawiona na zero, gniazdo utworzone dla rodziny adresów AF_INET6 może być używane do wysyłania i odbierania pakietów do iz adresu IPv6 lub adresu mapowanego IPv4. (podkreślenie moje)

questionAnswers(2)

yourAnswerToTheQuestion