在Unix网络编程中,有几个函数用来实现主机名与IP地址之间的转化,下面介绍gethostbyname:
#include <netdb.h>
struct hostent *gethostbyname(const char *hostname)
参数说明:
hostname指向一个字符串,该字符串就是需要查找host信息的主机名
返回值说明:
成功返回一个非空指针,出错返回NULL,同时设置h_errno(比如参数是不准确的主机名就会导致调用失败)。如果函数调用成功的话,就会返回一个指向hostent结构体的指针,我们所需要的信息就在这个结构体里面,所有很有必要了解这个结构体
struct hostent{
char * h_name; //h_name表示所查询主机的规范名字
char ** h_aliases; //h_aliases表示所查询主机的别名的列表,因为别名可能有多个
short h_addrtype; //h_addrtype表示所查询主机的IP地址的类型,函数仅支持IPv4,这一项固定是AF_INET
short h_length; //h_length表示IP地址的长度,IPv4的长度都为4,这项也是固定的
char ** h_addr_list; //h_addr_list表示IP地址的列表,因为一个主机可能有多个IP地址
};
结构如下图所示:
实例代码:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int main(int argc, char **argv)
{
struct hostent *ht;
char **alias;
char **addr;
char address[100];
ht = gethostbyname(argv[1]); //调用gethostbyname函数
if(ht == NULL) //调用失败则直接返回
{
printf("error\n");
return 0;
}
alias = ht->h_aliases;
addr = ht->h_addr_list;
printf("%s\n",ht->h_name); //打印主机的规范名
while(*alias != NULL) //循环打印主机的别名,可能有多个,也可能没有
{
printf("anc\n");
printf("size is %lu\n", strlen(*alias));
printf("one of aliases is %s\n", *alias);
*alias++;
}
printf("%d\n",ht->h_addrtype); //打印IP地址的类型,固定值为AF_INET,代表的整型值为2
printf("%d\n",ht->h_length); //打印IP地址的长度,在IPv4中为4个字节
while(*addr != NULL) //循环打印主机的IP地址,可能有多个
{
memset(address, '\0', 100);
inet_ntop(AF_INET, *addr, address, sizeof(address));
printf("one of addr is %s\n", address);
*addr++;
}
return 0;
}
gethostbyname的查询机制:
gethostbyname函数首先会根据/etc/hosts文件来查找指定主机的IP地址,如果查找不到,那么就会转到DNS服务器去查找,注意我们的查找结果与DNS服务器有关,打个比方,如果一个主机有5个IP地址,但是某个DNS服务器只收录了其中的三个,那么当我们以该DNS服务器作为查找节点时,就只会返回这三个IP地址,不再往下递归查询。整个查询过程的递归的,一直到查找成功或者查找失败,注意查找成功表示找到一个记录就算成功,它并不会将所有的记录全部查找出来。
获取错误信息:
如果gethostbyname函数调用失败,那么会设置全局变量h_errno的值(默认值为0,表示没有错误发生),我们可以根据这个值来打印错误信息。
h_errno的取值如下:
我们通过如下代码就可以得到错误信息:
if(ht == NULL)
{
printf("error\n");
printf("%s\n",hstrerror(h_errno));
return 0;
}
函数hstrerror会根据全局变量h_errno的值去查找对应的错误信息,它返回一个char指针,指向错误信息字符串(字符串的内容就是上面表格罗列的四条,可能根据系统不同而有所变化)。
存在的问题:
在我的实验过程中(实验环境是Ubuntu虚拟机),还存在一个问题,就是gethostbyname函数已经正常调用了,并且得到了正确的IP地址,然而全局变量h_errno会被设置HOST_NOT_FOUND,也就是说产生了Unknown host错误,这里还明白原因是什么,如果有了解的大神,希望能够解答一下。