TCP/IP网络编程 第八章:域名及网络地址

域名系统

这里对计算机网络小白简要的介绍一下域名系统,像我们平时上网用的都是类似于www.baidu.com的域名。就是说我们可以通过IP地址和域名同时访问一个网站,那么两则到底有何区别?其实可以这么理解,域名是IP地址的虚拟地址,而非实际地址。因此需要将虚拟地址转换成实际地址。这个转换的重任就是交给DNS服务器。

每台计算机中都有一台默认DNS服务器,如果计算机想要查询某一个域名对应的IP地址,它首先就会向默认DNS服务器发送查询请求,如果这台DNS服务器并不知道某一个域名对应的IP地址,它会向上一级DNS服务器查询。到达顶级DNS服务器后它肯定知道向哪个DNS发出请求。进而向下级DNS传递解析请求,得到IP地址后原路递归回去。最终计算机可以知道目标域名的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
}

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给同一域名,利用多个服务器进行负载均衡。此时同样可以通过此变量获取地址信息。

下面通过一个示例来进行演示:

#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结构体变量的地址值而非字符串。

利用IP地址获取域名

#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的实现

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中的函数完全一致。

你可能感兴趣的:(TCP/IP网络编程,网络,tcp/ip,服务器,网络协议)