这里对计算机网络小白简要的介绍一下域名系统,像我们平时上网用的都是类似于www.baidu.com的域名。就是说我们可以通过IP地址和域名同时访问一个网站,那么两则到底有何区别?其实可以这么理解,域名是IP地址的虚拟地址,而非实际地址。因此需要将虚拟地址转换成实际地址。这个转换的重任就是交给DNS服务器。
每台计算机中都有一台默认DNS服务器,如果计算机想要查询某一个域名对应的IP地址,它首先就会向默认DNS服务器发送查询请求,如果这台DNS服务器并不知道某一个域名对应的IP地址,它会向上一级DNS服务器查询。到达顶级DNS服务器后它肯定知道向哪个DNS发出请求。进而向下级DNS传递解析请求,得到IP地址后原路递归回去。最终计算机可以知道目标域名的IP地址。
这个问题回答了我们学习本章的原因。试想一个情景,我们在为一个公司开发一个客户端使用公司提供的服务。那么如果要使用公司的服务,那么肯定要访问公司的服务器。那么保存在客户端内部的是服务器域名还是服务器地址呢?系统运行时,保持IP地址并不容易,系统相关的各种原因会导致IP地址变更。那么由于变更,我们需要时时刻刻修改源代码中的IP地址,这对于一个不具有专业知识的使用者是不现实的。
一旦注册域名可能永久不变,因此利用域名编写程序会好一些。这样运行程序时根据域名获得IP地址,再接入服务器,这样程序就不会依赖于服务器IP地址了。所以说,程序中也需要IP地址和域名之间的转换函数。
通过以下函数可以通过传递字符串格式的域名来获取IP地址。
#include
struct hostnet * gethostbyname(const char*hostname);
//成功时返回houstnet结构体地址,失败时返回NULL指针
先介绍以下此结构体定义:
struct hostent{
char * h_name; //official name
char ** h_aliases; //alias list
int h_addrtype; //host address type
int h_length; //address length
char ** h_addr _list; //address list
}
下面通过一个示例来进行演示:
#include
#include
#include
#include
#include
void error_handling(char* message);
int main(int argc,char*argv[]){
int i;
struct hostent *host;
if(argc!=2){
printf("Usage : %s \n",argv[0]);
exit(1);
}
host=gethostbyname(argv[1]);
if(!host)error_handling("gethost...error");
printf("Official name: %s \n",host->name);
for(int i=0;host->h_aliases[i];i++)printf("Aliases %d: %s\n",i+1,host->aliases[i]);
printf("Address type: %s\n",(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
for(int i=0;host->h_addr_list[i];i++)
printf("IP addr %d: %s \n",i+1,inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
voie error_handling(char *message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
现在讨论上述示例的第26-28行。如果只看hostent结构体的定义,结构体成员h_addr_list指向字符串指针数组。但时字符串指针数组中的元素实际指向的时in_addr结构体变量的地址值而非字符串。
#include
struct hostent *gethostbyaddr(const char* addr,socklen_t len,int family);
//成功时返回hostent结构体变量地址,失败时返回NULL指针
addr //含有IP地址信息的in_addr结构体指针。为了同时传递IPv4地址以外的其他信息,该变量声明为char指针
len //第一个参数传递的地址信息的字节数
family //传递的地址族信息
下面通过示例来演示该函数的使用方法:
#include
#include
#include
#include
#include
#include
void error_handling(char *message);
int main(int argc, char *argv[]){
int i;
struct hostent *host;
struct sockaddr_in addr;
if(argc!=2){
printf("Usage : %s \n", argv[0]);
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr=inet_addr(argv[1]);
host=gethostbyaddr((char*)&addr.sin_addr,4, AF_INET);
if(!host)error handling("gethost... error");
printf("Official name: %s \n", host->h_name);
for(i=0; host->h_aliases[i]; i++)printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
printf("Address type: %s \n",(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
for(i=0; host->h_addr_list[i]; i++)
printf("IP addr %d: %s \n",i+1,inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
voie error_handling(char*message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
Windows平台中也有类似功能的同名函数。先介绍gethostbyname函数.
#include
struct hostent* gethostbyname(const char *name);
//成功返回hostent结构体变量地址值,失败时返回NULL指针
函数名,参数及返回类型与Linux中没有区别,介绍下一函数
#include
struct hostent* gethostbyaddr(const char* addr,int len,int family);
//成功时返回hostent结构体变量地址,失败时返回NULL指针
上述函数也于Linux中的函数完全一致。