c++ - IPv6 连接错误 WSAEAFNOSUPPORT

标签 c++ windows sockets winsock2

我使用主机名解析器为 IPv4/IPv6 编写了一个小型客户端。 对于 IPv4 和解析器,它很好,但在 connect() 时不适用于 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;
}

如果有人有想法,感谢阅读。

最佳答案

问题出在这里:

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

这会将 IPv6 地址写入 sin6_family 字段之上,破坏了整个结构。

应该是:

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

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

关于c++ - IPv6 连接错误 WSAEAFNOSUPPORT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49700784/

相关文章:

c++ - 在 C++ 中使用 XGBOOST

c++ - scanf 中的赋值顺序有保证吗?

c++ - 如何从移动捕获 lambda 表达式创建 std::function?

python - 无法在 tensorflow 中加载音频文件(Windows10)

c# - 服务错误 1053 : Could not start in timely fashion

java - 如何解码Netty中未知长度的缓冲区?

Python发送UDP数据包

c++ - 转换为常量类型,初始化一个数组

c - 链接器选项,路径总和太长?

c# - 为什么套接字在有更多字节可用时读取 0 个字节