问题描述
编辑:在检查 IPv6 Test 时,我发现我的 ISP 不提供 IPv6...否则这段代码很好
getaddrinfo()
对于 IPv6 总是失败,错误代码为 11268096,但对于 IPv4 是成功的。
设置 Hint.ai_family = AF_INET6;
是触发错误的原因,但我不知道为什么。
另外,我如何获得数字中的 sin_port
/sin6_port
?我总是得到端口 0。(正如@Remy Lebeau 指出的,我只要求域的 IP,所以它不会输出端口......)
void GetAddrInfoFromHostNameIPV6(const char* DomainName,addrinfo* Result,bool& IsSuccessful)
{
IsSuccessful = false;
addrinfo Hint;
addrinfo* Return = nullptr;
int ErrorCode;
memset(&Hint,sizeof(Hint));
Hint.ai_family = AF_INET6;
Hint.ai_socktype = SOCK_STREAM;
//Hint.ai_socktype = SOCK_DGRAM;
ErrorCode = getaddrinfo(DomainName,NULL,&Hint,&Return) << '\n';
if (ErrorCode != 0)
{
std::cout << "\n Error GetAddrInfoFromHostNameIPV6() Failed with Error Code: " << ErrorCode << " in GetAddrInfoFromHostName In: NW_P!";
}
else
{
*Result = *Return;
char IpAddress[INET6_ADDRSTRLEN];
uint16_t Port;
inet_ntop(AF_INET6,&((sockaddr_in6*)((Result)->ai_addr))->sin6_addr,IpAddress,INET6_ADDRSTRLEN);
Port = *(&((sockaddr_in6*)(Result->ai_addr))->sin6_port);
std::cout << "\n IPV6 Address of Domain '" << DomainName << "' Is " << IpAddress << " With Port: " << Port;
IsSuccessful = true;
}
if (!IsSuccessful)// For the safe of readability
{
std::cout << "\n Error GetAddrInfoFromHostName() Failed in NW_P!\n";
}
}
解决方法
您将错误代码向左移位 10 位,然后再将其分配给 ErrorCode
。
十进制 11268096
是二进制 101010111111000000000000
。注意到右边所有额外的零了吗?
您需要在 << '\n'
返回后去掉 getaddrinfo()
,它不属于那里,因为您没有在该行代码中将错误代码输出到 std::cout
。
去掉位移,真正的错误码是11004
(二进制10101011111100
),即WSANO_DATA
:
有效名称,没有请求类型的数据记录。请求的名称有效并且在数据库中找到,但没有正确的关联数据正在解析。通常的例子是使用 DNS(域名服务器)的主机名到地址转换尝试(使用 gethostbyname
或 WSAAsyncGetHostByName
)。返回一条 MX 记录但没有 A 记录——表明主机本身存在,但不能直接访问。
您可以将错误代码传递给 gai_strerror()
以获得错误消息输出的人类可读字符串,例如:
std::cout << "\n Error GetAddrInfoFromHostNameIPV6() Failed with Error Code: " << ErrorCode << " (" << gai_strerror(ErrorCode) << ") in GetAddrInfoFromHostName In: NW_P!";
至于端口号为 0,您不是要求 getaddrinfo()
解析任何服务名称/端口字符串作为输入(pServiceName
参数为 NULL),您只是要求翻译域名称转换为 IP,因此它不会输出任何端口号。域本身不使用端口号。端口号由在域/IP 指向的服务器上运行的服务(HTTP 等)使用。
附带说明,您正在泄露 addrinfo
输出的 getaddrinfo()
列表。使用完列表后,您需要调用 freeaddrinfo()
。