如何通过域名获取主机ip地址
需要注意,主机
不是本机,一般指服务器与客户端。主机信息主要包含ip地址
和对应的域名
。linux使用结构体struct hostent
表示主机的信息。struct hostent
各个成员的含义如下:
struct hostent
{
char *h_name; //主机名,即官方域名,规范域名
char **h_aliases; //主机所有别名构成的字符串数组,同一IP可绑定多个域名。最后以一个字符串为NULL,用于判断数组的结束。
int h_addrtype; //主机IP地址的类型.要么是AF_INET(IPV4),要么是AF_INET6(IPV6).
int h_length; //主机IP地址长度,IPV4地址为4,IPV6地址则为16
char **h_addr_list;//域名对应ip地址表,以网络字节序存储。最后一个数组的指针为NULL,用来判断数组的结束。即h_addr_list[n] == NULL。若要打印出这个IP,需要调用inet_ntoa()。
};
下面是获取主机信息的相关函数,使用时需要包含netdb.h
:
struct hostent *gethostbyname(const char *name)
- 通过域名(如"www.baidu.com")获取IP地址详细信息。此函数多线程不安全,建议使用gethostbyname_r()函数代替。
- name:域名字符串。
- 成功返回信息体指针。失败返回NULL.失败时可以通过全局变量
h_errno
查看具体原因。
struct hostent *gethostbyname2(const char *name, int af)
- 功能类似gethostbyname().但是调用者可以指定地址族。此函数多线程不安全,建议使用gethostbyname2_r()函数代替。
- af:指定地址族。要么是AF_INET(IPV4),要么是AF_INET6(IPV6)
struct hostent *gethostbyaddr(const void *addr,socklen_t len, int type)
- 通过地址来获取IP地址的详细信息。此函数多线程不安全,建议使用gethostbyaddr_r()函数代替。
- addr:ip数值地址(大端格式)。一般用inet_aton()函数来生成。
- len:addr的字节数。即如果是IPv4,则为4四个字节.
- type:指定地址的格式。要么是AF_INET(IPV4),要么是AF_INET6(IPV6)。
- 成功返回信息体指针。失败返回NULL.失败时可以通过全局变量
h_errno
查看具体原因。
int gethostbyname_r(const char *name,struct hostent *ret, char *buf, size_t buflen,struct hostent **result, int *h_errnop)
- 是gethostbyname()的升级版本。多线程安全。功能和gethostbyname()类似。
- ret:如果获取成功,相关信息会填充到此结构体。
- buf:函数的临时工作buff.
- buflen:buf的长度。
- result:如果成功,会指向转换后的结果指针。失败返回0.
- h_errnop:存储错误码。
- return:成功返回0.失败返回错误码,如果为ERANGE,表示buf大小不够。
int gethostbyname2_r(const char *name, int af,struct hostent *ret, char *buf, size_t buflen,struct hostent **result, int *h_errnop)
- 功能和参数gethostbyname_r()相似。
int gethostbyaddr_r(const void *addr, socklen_t len, int type,struct hostent *ret, char *buf, size_t buflen,struct hostent **result, int *h_errnop)
- 参数含义参看gethostbyname_r()。功能参看gethostbyaddr().
下面是函数使用例程:
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
void main(void)
{
struct hostent *pInfo = NULL;
pInfo = gethostbyname("www.baidu.com");
printf("%d ",pInfo->h_length);
printf("%d ",pInfo->h_addrtype);
printf("%s\n",pInfo->h_name);//主机域名
printf("别名:");
for(int i = 0; pInfo->h_aliases[i];i++){//打印别名表
printf("%s ",pInfo->h_aliases[i]);
}
printf("\nip地址:");
for(int i = 0; pInfo->h_addr_list[i];i++){//打印ip地址表printf("%s ",inet_ntoa(*(struct in_addr*)pInfo->h_addr_list[i])); }
struct hostent *hp;
size_t hstbuflen;
char *tmphstbuf;
int res;
int herr;
pInfo = malloc (sizeof (struct hostent));
hstbuflen = 1024;
tmphstbuf = malloc (hstbuflen);
res = gethostbyname_r("www.baidu.com",pInfo,tmphstbuf,hstbuflen,&hp,&herr);
printf("%s\n",pInfo->h_name);
printf("%s\n",hp->h_name);
}
除此之外,本机主机在/etc/hosts
的主机数据库文件中保存了一个主机名查询静态表。可以使用命令cat /etc/hosts
查看。它是Linux系统上一个负责ip地址与域名快速解析的文件。hosts文件包含了ip地址与主机名之间的映射,还包括主机的别名。在没有域名解析服务器的情况下,系统上的所有网络程序都通过查询该文件来解析对应于某个主机名的ip地址,否则就需要使用dns服务程序来查找。可以通过将常用的域名和ip地址映射加入到hosts文件中,实现快速方便的访问。系统查询域名的优先级为dns缓存 > hosts文件 > dns服务
.除此之外,也可以使用下面的函数在程序中查看映射表。
void sethostent(int stayopen)
- 打开数据库,并设置起始值。
struct hostent *gethostent(void)
- 获取主机数据库中的下一个条目。
void endhostent(void)
- 关闭主机数据库。
下面是数据库查看的使用例程:
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
void main(void)
{
struct hostent *pInfo = NULL;
sethostent(0);
int index = 0;
while(1){
pInfo = gethostent();
if(pInfo == NULL){
break;
}
printf("-----------%2d------------\n",++index);
printf("%s\n",pInfo->h_name);
printf("别名:");
for(int i = 0; pInfo->h_aliases[i];i++){
printf("%s ",pInfo->h_aliases[i]);
}
printf("\nip地址:%d ",pInfo->h_addrtype);
char strbuf[32];
for(int i = 0; pInfo->h_addr_list[i];i++){
const char *pStr = inet_ntop(pInfo->h_addrtype,pInfo->h_addr_list[i],strbuf,32);
if(pStr){
printf("%s ",pStr);
}
}
printf("\n");
}
endhostent();
}