域名及网络地址
域名系统
DNS(Domain Name System :域名系统)是对IP地址和域名进行相互转换的系统,其核心是DNS服务器。
什么是域名
提供网络服务的服务器端也是通过IP地址区分的,但几乎不可能以非常难记的IP地址形式交换服务器端地址信息。
DNS服务器
在浏览器地址栏中输入Naver网站的IP地址222.122.195.5即可浏览Naver网站主页。但我们通常输入网站的域名www.naver.com访问网站。
域名是赋予服务器端的虚拟地址,而非实际地址。因此,需要将虚拟地址转化为实际地址。那如何将域名变为IP地址呢?
DNS服务器担此重任,可以向DNS服务器请求转换地址。所有计算机中都记录着默认DNS服务器地址,就是通过这个默认DNS服务器得到相应域名的IP地址信息。在浏览器地址栏中输入域名后,浏览器通过默认DNS服务器获取该域名对应的IP地址信息,真正接入该网站。
ping www.naver.com
这样可知道某一域名对应的IP地址。
先执行命令nslookup,再输入server可以获得计算机中注册的默认DNS服务器地址。
计算机内置的默认DNS服务器并不知道网络上所有域名的IP地址信息。若该DNS服务器无法解析,则会询问其他DNS服务器,并提供给用户
上图展示了默认DNS服务器无法解析主机询问的域名IP地址时的应答过程:
默认DNS服务器收到无法解析的请求时,向上级DNS服务器询问,通过这种方式逐级向上传递信息,到达顶级DNS服务器——根DNS服务器时,它知道向哪个DNS服务器访问。向下级DNS服务器传递解析请求,得到IP地址后原路返回,最后将解析的IP地址传递到发起请求的主机。
DNS就是这样层次化管理的一种分布式数据库系统。
IP地址和域名之间的转换
为什么使用域名?
IP地址比域名发生变更的概率要高,所以利用IP地址编写程序并非上策。域名注册后可能永久不变,因此利用域名编写程序会好一些。每次运行程序时根据域名获取IP地址,再接入服务器,这样程序就不会依赖于服务器IP地址了。所以说程序中需要IP地址和域名之间的转换函数。
解析器和名字服务器
常见的解析器函数:gethostbyname和gethostbyaddr,前者把主机名映射称IPv4地址,后者执行相反的映射。
下图展示了应用程序,解析器和名字服务器之间的典型关系:
利用域名获取IP地址
使用以下函数可以通过传递字符串格式的域名获取IP地址。
此函数传递域名字符串,返回域名对应的IP地址。返回时,地址信息装入hostent结构体。结构体定义如下:
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
}
域名转换只需关注h_addr_list。
结构体各成员:
h_name: 该变量中存放官方域名。官方域名代表某一主页。
h_aliases: 可以通过多个域名访问 同一主页,同一IP可以绑定多个域名。
h_addrtype: gethostbyname函数不仅支持IPv4,也支持IPv6。通过此变量获取保存在h_addr_list的IP地址的地址族信息。
h_length:保存IP地址的长度。IPv4是4字节,IPv6是16字节。
h_addr_list: 最重要的成员,整数形式保存域名对应的IP地址。用户较多的网站有可能分配多个IP给同一域名,利用多个服务器进行负载均衡。
调用gethostbyname函数后返回hostent结构体的变量结构如下图:
/* gethostbyname函数的应用:并说明hostent结构体变量的特性 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netdb.h>
void error_handling(char *message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
int main(int argc,char *argv[])
{
int i;
struct hostent *host;
if (argc != 2)
{
printf("Usage: %s <addr> \n",argv[0]);
exit(1);
}
host = gethostbyname(argv[1]);
if (!host)
error_handling("gethostbyname() 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++) //输出IP地址信息
printf("IP addr %d: %s \n",i+1,inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
运行结果:
若只看hostent结构体的定义,结构体成员h_addr_list指向字符串指针数组。但字符串指针数组中的元素实际指向的是in_addr结构体变量地址而非字符串。如图所示:
利用IP地址获取域名
gethostbyaddr函数利用IP地址获取域相关信息。
/* gethostbyaddr函数的应用 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netdb.h>
void error_handling(char *message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
int main(int argc,char *argv[])
{
int i;
struct hostent *host;
struct sockaddr_in addr;
if (argc != 2)
{
printf("Usage: %s <addr> \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("gethostbyaddr() 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++) //输出IP地址信息
printf("IP addr %d: %s \n",i+1,inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
先通过ping获得Google的IP地址,并利用此信息运行示例:
完
还没有评论,来说两句吧...