在网络编程中,有时需要通过域名或者主机名来获取IP地址。
以为通常使用gethostbyname() API。
但是今天碰到了一个BUG,使我觉得应该在有这种需求的时候,使用getaddrinfo()而不是gethostbyname()。
我在ubuntu虚拟机中,通过gethostbyname(),传入参数为主机名,想要获取主机的IP地址。
gethostbyname()返回的struct hostent指针不为NULL,但是只要访问struct hostent指针中的任何成员,都会段错误。
对于这个段错误我没有找到原因。
如果gethostbyname()无法获取主机名对应的地址信息,为什么不返回NULL,现在返回了指针却不能访问,
如果在真实项目中,岂不是GG。
之前我遇到过虚拟机ping不通主机的情况,把主机的防火墙关掉就行了。
这次即使关了主机的防火墙,还是一直段错误。
如果参数是百度的域名,就可以正常访问返回的指针。
这里,我很不明白的点,不在与无法获取主机地址,而在于为什么gethostbyname()返回的非空指针会段错误。
将gethostbyname()改为使用getaddrinfo(),再传入主机名,会返回一个错误:
此处,我认为,API返回一个错误,没有问题,说明我哪里的配置有问题。
但是,它没有段错误,这让程序更可靠了。
基于这个原因,要使用getaddrinfo()获取地址。
为了便于阅读,我将一个函数中的代码,拆分成几段。
这里我本想用gethostname()获取自己的hostname,然后再根据hostname获取自己的IP地址的
char buff[MIN_BUFFSISE] = {0x00};
sockaddr_in local_addr, addr;
socklen_t len = sizeof(sockaddr_in);
// local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
char local_host_name[256] = { 0x00 };
if(gethostname(local_host_name, 256))
{
perror("gethostname");
return -1;
}
std::cout << "gethostname:" << local_host_name << std::endl;
使用getaddrinfo()通过主机名获取主机IP,报错,没有段错误
代码参考:getaddrinfo函数实现域名解析
int rv;
struct addrinfo hints;
struct addrinfo *ai_list = NULL, *tmp_ptr = NULL;
struct sockaddr_in *sin;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// rv = getaddrinfo(local_host_name, NULL, &hints, &ai_list);
rv = getaddrinfo("LAPTOP-6UC841M5", NULL, &hints, &ai_list); //这里我尝试用主机名获取主机地址,失败了,并报错,程序没有崩溃
// rv = getaddrinfo("192", NULL, &hints, &ai_list);
if (rv != 0)
{
std::cout << "error:" << gai_strerror(rv) << std::endl;
return -1;
}
sin = (struct sockaddr_in *)ai_list->ai_addr;
std::cout << inet_ntoa(sin->sin_addr) << std::endl;
tmp_ptr = ai_list;
while (tmp_ptr->ai_next != NULL)
{
tmp_ptr = tmp_ptr->ai_next;
sin = (struct sockaddr_in *)tmp_ptr->ai_addr;
std::cout << inet_ntoa(sin->sin_addr) << std::endl;
}
使用gethostbyname()同过主机名获取主机IP,没有报错,但是段错误
#if 0 //使用gethostbyname()
// struct hostent *phost = gethostbyname(local_host_name);
struct hostent *phost = gethostbyname("LAPTOP-6UC841M5");
// struct hostent *phost = gethostbyname("www.baidu.com");
std::cout << "1:" << std::endl;
strerror(h_errno);
if(phost == NULL) //这里是可以顺利同过的,指针非空
{
strerror(h_errno);
}
std::cout << "2:" << std::endl; //从这之后,任何对指针成员的访问,都会段错误
if(phost->h_name == NULL)
std::cout << "phost->h_name is NULL " << std::endl;
std::cout << phost->h_length << std::endl;
std::cout << "3:" << std::endl;
int i = 0;
for (i = 0;; i++)
{
std::cout << inet_ntoa(*(in_addr *)phost->h_addr_list[i]) << std::endl;
if (phost->h_addr_list[i] + phost->h_length >= phost->h_name)
break;
}
// while (phost->h_addr_list[i] != 0)
// {
// addr.sin_addr.s_addr = *(uint32_t *)phost->h_addr_list[i++];
// std::cout << "gethostbyname:" << inet_ntoa(addr.sin_addr) << std::endl;
// }
#endif
getchar();
getaddrinfo()函数使用详解以及注意事项