1、域名系统
DNS是对IP地址和域进行相互转换的系统,其核心是DNS服务器。
什么是域名
提供网络服务的服务器端也是通过IP地址区分的,但几乎不可能以非常难记 的IP地址形式交换服务器端地址信息。因此,将容易记、易表述的域名分配并取代地址。
DNS服务器
在浏览器地址栏中输入Naver网站的IP地址222.122.195.5即可浏览Naver网站主页。但我们通常输入Naver网站的域名www.naver.com访问网站。二者之间究竟有何区别?
从进入Naver网站主页这一结果看,没有区别,但接入过程不同。域名是赋予服务器端的虚拟地址,而非实际地址。因此,需要将虚拟地址转化为实际地值。那如何将域名变为IP地址呢?DNS服务器但此重任,可以向DNS服务器请求转换地址。
所有计算机都记录着默认DNS服务器地址,浏览器通过这个默认DNS服务器得到相应域名的IP地址信息。在浏览器地址栏中输入域名后,浏览器通过DNS服务器获取该域名对应的IP地址信息,之后才真正接入该网站。
计算机内置的默认DNS服务器并不知道网络上所有域名的IP地址信息。若该DNS服务器无法解析,则会询问其他NDS服务器,并提供给用户,如图8-1所示。
上图展示了默认DNS服务器无法解析主机询问的域名IP地址时的应答过程。可以看出,默认DNS服务器收到自己无法解析的请求时,向上级DNS服务器询问。通过这种方式逐级向上传递信息,到达顶级DNS服务器——根DNS服务器时,它知道该向哪个DNS服务器询问。向下级DNS传递解析请求,得到IP地址后原路返回,最后将解析的IP地址传递到发起请求的主机。DNS就是这样层次化管理的一种分布式数据库系统。
上一小节讲解了域名和IP弟子之间的转换过程,本节介绍通过程序向DNS服务器发出解析请求的方法。
利用域名获取IP地址
使用以下函数可以通过传递字符串格式的域名获取IP地址。
#include <netdb.h>
struct hostent* gethostbyname(const char *hostname);
/*
* 成功时返回hostent结构体地址,失败时返回NULL指针
*/
这个函数使用方便。只要传递域名字符串,就会返回域名对应的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
}
从上述结构体定义中可以看出,不只返回IP信息,同时还连带着其他信息。各位不用想得太过复杂。域名转IP时只需关注h_addr_list。喜爱按简要说明上述结构体各成员。
h_name
该变量中存有官方域名(Official domain name)。官方域名代表某一主页,但实际上,一些著名公司的域名并未用官方域名注册。
h_aliases
可以通过多个域名访问同一主页。同一IP可以绑定多个域名,因此,除官方域名外还可指定其他域名。这些信息可以通过h_aliases获得。
h_addrtype
gethostbyname函数不仅支持IPv4,还支持IPv6。因此可以通过此变量获取保存在h_addr_list的IP地址的地址族信息。若是IPv4,则此变量存有AF_INET。
h_length
保存IP地址长度。若是IPv4地址,因为是4个字节,则保存4;IPv6时,因为是16个字节,故保存16.
h_addr_list
这是最重要的成员。通过此变量以整数形式保存域名对应的IP地址。另外,用户较多的网站有可能分配多个IP给同一域名,利用多个服务器进行负载均衡。此时同样可以通过此变量获取IP地址信息。
利用IP地址获取域名
之前介绍的gethostbyname函数利用域名获取包括IP地址在内的域相关信息。而gethostbyaddr函数利用IP地址获取域相关信息。
#include <netdb.h>
struct hostent* gethostbyaddr(const char* addr, socklen_t len, int family);
/*
* 成功时返回hostent结构体变量地址值,失败时返回NULL指针
* addr 含有IP地址信息的in_addr结构体指针。为了同时传递IPv4地址之外的其他信息,该变量的类型声明为char指针
* len 向第一个参数传递的地址信息的字节数,IPv4时为4,IPv6时为16
* family 传递地址族信息,IPv4时为AF_INET,IPv6时为AF_INET6
*/
// man 手册好像改了
struct hostent *gethostbyaddr(const void *addr,
socklen_t len, int type);