Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/204.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ IPv6连接错误WSAEAFNOSUPPORT_C++_Windows_Sockets_Winsock2 - Fatal编程技术网

C++ IPv6连接错误WSAEAFNOSUPPORT

C++ IPv6连接错误WSAEAFNOSUPPORT,c++,windows,sockets,winsock2,C++,Windows,Sockets,Winsock2,我使用主机名解析程序为IPv4/IPv6编写了一个小客户端。 对于IPv4和解析器,连接()时可以,但对于IPv6则不行。我有一个问题WSAGetLastError()说WSAEAFNOSUPPORT 我有一个将所有结构(AF_INET->AF_INET6,SOCKADDR_IN->SOCKADDR_IN6)切换到IPv6版本的交换机 #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, "ws

我使用主机名解析程序为IPv4/IPv6编写了一个小客户端。 对于IPv4和解析器,连接()时可以,但对于IPv6则不行。我有一个问题WSAGetLastError()说WSAEAFNOSUPPORT

我有一个将所有结构(AF_INET->AF_INET6,SOCKADDR_IN->SOCKADDR_IN6)切换到IPv6版本的交换机

#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

int main()
{
    printf("Simple_Client IPv4 & IPv6\n\n");

    // Initiates Winsock
    WSADATA WSAData;
    WSAStartup(MAKEWORD(2, 0), &WSAData);

    // Get Parameters IP/PORT and request
    std::string str_HOSTNAME = "mirror.neostrada.nl";
    int PORT = 21;

    // RESOLVE IP
    BOOL is_IPv6 = FALSE;
    std::string str_dest_ip = "";

    addrinfo hints = { 0 };
    hints.ai_flags = AI_ALL;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    addrinfo * pResult;
    getaddrinfo(str_HOSTNAME.c_str(), NULL, &hints, &pResult);

    if (pResult == NULL)
    {
        printf("pResult error\n");
        return -1;
    }

    if (pResult->ai_family == AF_INET)
    {
        printf("getaddrinfo = AF_INET (IPv4)\n");
        is_IPv6 = FALSE;
    }

    if (pResult->ai_family == AF_INET6)
    {
        printf("getaddrinfo = AF_INET6 (IPv6)\n");
        is_IPv6 = TRUE;
    }

    char str[128];
    memset(str, 0, sizeof(str));

    if (is_IPv6 == FALSE) // IPv4
    {
        if (inet_ntop(AF_INET, &(*((ULONG*)&(((sockaddr_in*)pResult->ai_addr)->sin_addr))), str, INET_ADDRSTRLEN))
            str_dest_ip = char_to_string(str, strlen(str)); // Copy char in std::string
        else
            printf("inet_ntop error\n");
    }

    if (is_IPv6 == TRUE) // IPv6
    {
        if (inet_ntop(AF_INET6, &(*((ULONG*)&(((sockaddr_in6 *)pResult->ai_addr)->sin6_addr))), str, INET6_ADDRSTRLEN))
            str_dest_ip = char_to_string(str, strlen(str)); // Copy char in std::string
    }

    printf("%s : %s | Port : %i\n", is_IPv6 ? "IPv6" : "IPv4", str_dest_ip.c_str(), PORT);

    // Connect to the HOSTNAME
    SOCKET sock;

    if (is_IPv6 == TRUE)
    {
        SOCKADDR_IN6 sin;
        sin.sin6_family = AF_INET6;

        if(inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin) != 1)
            printf("ERROR inet_pton %i\n", WSAGetLastError());

        sin.sin6_port = htons(PORT);
        sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
        if (sock == INVALID_SOCKET)
            return -2;

        if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) != SOCKET_ERROR)
        {
            printf("Connect Success to %s | PORT : %i\n", str_dest_ip.c_str(), PORT);
        }
        else
        {
            printf("ERROR connect to %s | PORT : %i : %i\n", str_dest_ip.c_str(), PORT, WSAGetLastError());
            Sleep(10000);
            return -2;
        }
    }

    char buf[1024] = { 0 };

    int size_recv = recv(sock, buf, sizeof(buf), 0);

    printf("SIZE RECV = %i | DATA RECV = %s\n", size_recv, char_to_string(buf, size_recv).c_str());

    WSACleanup();
    getchar();
    return 0;
}
#包括
#包括
#pragma注释(lib,“ws2_32.lib”)
int main()
{
printf(“简单客户端IPv4和IPv6\n\n”);
//启动Winsock
WSADATA WSADATA;
WSAStartup(MAKEWORD(2,0)和WSAData);
//获取参数IP/端口和请求
std::string str_HOSTNAME=“mirror.neostrada.nl”;
int端口=21;
//解析IP
BOOL是_IPv6=FALSE;
std::string str_dest_ip=“”;
addrinfo提示={0};
hits.ai_flags=ai_ALL;
hits.ai_family=AF_unsec;
hits.ai_socktype=SOCK_流;
hits.ai_protocol=IPPROTO_TCP;
addrinfo*preslt;
getaddrinfo(str_HOSTNAME.c_str(),NULL,&提示,&预设);
如果(PRESLT==NULL)
{
printf(“预设错误\n”);
返回-1;
}
如果(预设->ai_族==AF_INET)
{
printf(“getaddrinfo=AF_INET(IPv4)\n”);
is_IPv6=FALSE;
}
如果(预设->ai_族==AF_INET6)
{
printf(“getaddrinfo=AF_INET6(IPv6)\n”);
是_IPv6=TRUE;
}
char-str[128];
memset(str,0,sizeof(str));
if(is_IPv6==FALSE)//IPv4
{
如果(内部地址(AF内部地址和(*(ULONG*)和((sockaddr*)预设->ai内部地址)->sin内部地址)),str,内部地址trlen)
str_dest_ip=char_to_string(str,strlen(str));//在std::string中复制字符
其他的
printf(“inet_ntop error\n”);
}
如果(is_IPv6==TRUE)//IPv6
{
如果(inet\u ntop(AF\u INET6,&(*(ULONG*)和((sockaddr\u in6*)PRESLT->ai\u addr)->sin6\u addr)),str,INET6\u ADDRSTRLEN)
str_dest_ip=char_to_string(str,strlen(str));//在std::string中复制字符
}
printf(“%s:%s |端口:%i\n”,是IPv6吗?“IPv6”:“IPv4”,str_dest_ip.c_str(),端口);
//连接到主机名
插座;
if(is_IPv6==TRUE)
{
SOCKADDR_in 6 sin;
sin.sin6_family=AF_INET6;
if(inet_pton(sin.sin6_系列,str_dest_ip.c_str(),&sin)!=1)
printf(“错误inet\u pton%i\n”,WSAGetLastError());
sin.sin6_端口=htons(端口);
sock=套接字(AF_INET6、sock_流、IPPROTO_TCP);
if(sock==无效的_套接字)
返回-2;
if(connect(sock,(struct sockaddr*)&sin,sizeof(sin))!=SOCKET\u错误)
{
printf(“成功连接到%s |端口:%i\n”,str_dest_ip.c_str(),端口);
}
其他的
{
printf(“错误连接到%s |端口:%i:%i\n”,str_dest_ip.c_str(),端口,WSAGetLastError());
睡眠(10000);
返回-2;
}
}
char buf[1024]={0};
int size_recv=recv(sock,buf,sizeof(buf),0);
printf(“SIZE RECV=%i | DATA RECV=%s\n”,SIZE_RECV,char_to_string(buf,SIZE_RECV).c_str());
WSACleanup();
getchar();
返回0;
}
如果有人有想法,感谢阅读。

问题在于:

inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin)
这会将IPv6地址写入sin6_族字段的顶部,从而破坏整个结构

应该是:

inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin.sin6_addr)
在开始时对整个
sin
结构进行零初始化也是一个好主意,因为它的字段比您要填写的要多。

问题在于:

inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin)
这会将IPv6地址写入sin6_族字段的顶部,从而破坏整个结构

应该是:

inet_pton(sin.sin6_family, str_dest_ip.c_str(), &sin.sin6_addr)

在开始时对整个
sin
结构进行零初始化也是一个好主意,因为它的字段比您要填写的要多。

您没有正确使用
getaddrinfo()

首先,
getaddrinfo()
返回一个您忽略的错误代码

另一方面,
getaddrinfo()
返回一个链接列表,由于使用
AF\u unsec
,该列表可能在IPv4和/或IPv6的混合中包含多个地址。如果您只对IPv6感兴趣,请将
hints.ai_family
设置为
AF_INET6
,而不是
AF_unsec

但无论如何,一个给定的主机名可能有多个与之关联的IP,并且可能无法从您的位置访问所有IP,因此您应该
connect()
”访问列表中的每个地址,一次一个或并行一个,直到其中一个成功

此外,在这种情况下根本不需要使用
inet\u pton()
(正如@rustyx的回答所解释的,您没有正确使用)
getaddrinfo()
返回(6)中完全填充的
sockaddr\u
结构,可以按原样传递给
connect()

请尝试类似以下内容:

#include <winsock2.h>
#include <ws2tcpip.h>

#include <iostream>
#include <string>

#pragma comment(lib, "ws2_32.lib")

std::string addr_to_str(addrinfo *addr)
{
    char str[128];

    switch (addr->ai_family)
    {
        case AF_INET: // IPv4
        {
            if (inet_ntop(AF_INET, &(((sockaddr_in*)(addr->ai_addr))->sin_addr), str, INET_ADDRSTRLEN))
                return str;

            ret = WSAGetLastError();
            break;
        }

        case AF_INET6: // IPv6
        {
            if (inet_ntop(AF_INET6, &(((sockaddr_in6*)(addr->ai_addr))->sin6_addr), str, INET6_ADDRSTRLEN))
                return str;

            ret = WSAGetLastError();
            break;
        }

        default:
            ret = WSAEAFNOSUPPORT;
            break;
    }

    std::cerr << "inet_ntop error: " << ret << std::endl;
    return "";
}

int main()
{
    std::cout << "Simple_Client IPv4 & IPv6" << std::endl << std::endl;

    // Initiates Winsock
    WSADATA WSAData;
    int ret = WSAStartup(MAKEWORD(2, 0), &WSAData);
    if (ret != 0)
    {
        std::cerr << "WSAStartup error: " << ret << std::endl;
        return -1;
    }

    // Get Parameters IP/PORT and request
    std::string str_HOSTNAME = "mirror.neostrada.nl";
    int PORT = 21;

    // RESOLVE IP    
    addrinfo hints = { 0 };
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    addrinfo *pResult = NULL;
    ret = getaddrinfo(str_HOSTNAME.c_str(), std::to_string(PORT).c_str(), &hints, &pResult);
    if (ret != 0)
    {
        std::cerr << "getaddrinfo error: " << ret << std::endl;
        WSACleanup();
        return -1;
    }

    // Log the IPs
    bool has_IPv4 = false;
    bool has_IPv6 = false;

    for (addrinfo *addr = pResult; addr != NULL; addr = addr->ai_next)
    {
        switch (addr->ai_family)
        {
            case AF_INET: // IPv4
            {
                has_IPv4 = true;
                std::cout << "IPv4 : " << addr_to_str(addr);
                break;
            }

            case AF_INET6: // IPv6
            {
                has_IPv6 = true;
                std::cout << "IPv6 : " << addr_to_str(addr);
                break;
            }
        }
    }

    // Connect to the HOSTNAME
    SOCKET sock = INVALID_SOCKET;

    if (has_IPv6)
    {
        // try IPv6 first...
        for (addrinfo *addr = pResult; addr != NULL; addr = addr->ai_next)
        {
            if (addr->ai_family != AF_INET6)
                continue;

            std::cout << "Connecting to IPv6 : " << addr_to_str(addr) << " | Port : " << PORT << std::endl;

            sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
            if (sock == INVALID_SOCKET)
            {
                ret = WSAGetLastError();
                std::cerr << "socket error: " << ret << std::endl;
                continue;
            }

            if (connect(sock, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR)
            {
                ret = WSAGetLastError();
                std::cerr << "connect error: " << ret << std::endl;
                closesocket(sock);
                sock = INVALID_SOCKET;
                continue;
            }

            break;
        }
    }

    if ((sock == INVALID_SOCKET) && (has_IPv4))
    {
        // try IPv4 next...
        for (addrinfo *addr = pResult; addr != NULL; addr = addr->ai_next)
        {
            if (addr->ai_family != AF_INET)
                continue;

            std::cout << "Connecting to IPv4 : " << addr_to_str(addr) << " | Port : " << PORT << std::endl;

            sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
            if (sock == INVALID_SOCKET)
            {
                ret = WSAGetLastError();
                std::cerr << "socket error: " << ret << std::endl;
                continue;
            }

            if (connect(sock, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR)
            {
                ret = WSAGetLastError();
                std::cerr << "connect error: " << ret << std::endl;
                closesocket(sock);
                sock = INVALID_SOCKET;
                continue;
            }

            break;
        }
    }

    freeaddrinfo(pResult);

    if (sock == INVALID_SOCKET)
    {
        WSACleanup();
        return -2;
    }

    std::cout << "Connect Successful" << std::endl;

    char buf[1024];

    int size_recv = recv(sock, buf, sizeof(buf), 0);
    if (size_recv == SOCKET_ERROR)
    {
        ret = WSAGetLastError();
        std::cerr << "recv error: " << ret << std::endl;
    }
    else
    {
        std::cout << "SIZE RECV = " << size_recv;
        if (size_recv > 0)
        {
            std::cout << " | DATA RECV = ";
            std::cout.write(buf, size_recv);
        }
        std::cout << std::endl;
    }

    closesocket(sock);
    WSACleanup();

    std::cin.get();
    return 0;
}
#包括
#包括
#包括
#包括
#pragma注释(lib,“ws2_32.lib”)
std::字符串addr_to_str(addrinfo*addr)
{
char-str[128];
开关(地址->人工智能系列)
{
案例AF_INET://IPv4
{
如果(内部地址(AF_inet,&((sockaddr_in*)(addr->ai_addr))->sin_addr,str,内部地址trlen))
返回str;
ret=WSAGetLastError();
打破
}
案例6://IPv6
{
如果(inet_ntop(AF_INET6,&((sockaddr_in6*)(addr->ai_addr))->sin6_addr),str,INET6_ADDRSTRLEN)
返回str;
ret=WSAGetLastError();
打破
}
违约:
ret=WSAEAFNOSUPPORT;
打破
}

std::cerr您没有正确使用
getaddrinfo()

首先,
getaddrinfo()
返回一个您忽略的错误代码

另一方面,
getaddrinfo()
返回一个链接列表,由于您使用了
AF\u unsec
,该列表可能包含IPv4和/或IPv6混合的多个地址。如果您只对IPv6感兴趣,请设置<