您的位置:首页 > 理论基础 > 计算机网络

TCP/IP网络编程 学习笔记_9 --域名系统(DNS)

2015-08-12 19:38 771 查看

域名系统

什么是域名:我们网络通信底层最终还是通过IP地址来确认通信目标的,但以数字命名的IP地址非常难记,因此,我们就有了容易记,易表述的域名来取代IP地址。如,百度域名就是:www.baidu.com,而它的IP地址为:180.97.33.107,用这两种任何一种访问都是一样的效果。

DNS服务器

1,DNS即Domain Name System,它是一个可以对IP地址和域名进行相互转换的系统。

2,我们要打开一个网页,一般过程是:在浏览器地址栏输入域名地址(www.baidu.com),确认访问,然后它就会通过计算机默认的DNS服务器将这个域名地址转换为对应的IP地址信息,之后才能真正接入该网站。

然而,计算机内置的默认DNS服务器并不知道网络上所有域名的IP地址信息。若该DNS服务器无法解析,则会询问其他DNS服务器。这个过程是这样的:当默认DNS服务器收到自己无法解析的请求时,它会向上级DNS服务器询问,一层一层逐级向上传递信息,直到到达顶级DNS服务器(根DNS服务器)时,它就知道该向哪个DNS服务器询问。然后,向下级DNS传递解析请求,得到IP地址后原路返回,最后将解析的IP地址传递到发起请求的主机。DNS就是这样层次化管理的一种分布式数据库系统。示意图如下:



3,小操作:

如果想知道某一域名对应的IP地址信息,我们可以在控制台窗口输入如下内容:ping www.baidu.com




ping命令虽然是用来验证IP数据报是否到达目的地的,但执行过程中会同时经过域名到IP地址的转换过程,因此,可以通过此命令查看IP地址。

如果想知道自己计算机中注册的默认DNS服务器地址,可以输入如下命令:nslookup(如果是Linux系统,还需要进一步输入server)



IP地址和域名之间的转换

程序中为什么多选择使用域名而不是IP,这是因为一般IP地址容易变更。如果这样,那么一旦IP发生变化,用户就得重新下载你的应用程序了。所以用域名,一般域名注册了就可能永远不变,这样,每次运行程序时根据域名获取IP地址,再接入服务器,这样程序就不会依赖于服务器IP地址了。下面,我们就来分别看看IP与域名之间到底怎么转换。

利用域名获取IP地址

struct hostent * gethostbyname(const chat *hostname);

成功时返回hostent结构体地址,失败返回NULL指针


hostname:域名字符串

struct hostent

{

char * h_name; //官方域名

char ** h_aliases; //其它域名,同一IP可以绑定多个域名

int h_addrtype; //地址族信息

int h_length; //IP地址长度,是IPv4则保持4,IPv6则保持16字节

char ** h_addr_list; //整数形式保存域名对应的IP地址,用户较多的网站可能分配多个IP给同一域名,利用多个服务器进行负载均衡。

}

实例代码:

//
//  main.cpp
//  hello_client
//
//  Created by app05 on 15-8-12.
//  Copyright (c) 2015年 app05. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>

void error_handling(char *message);

int main(int argc, const char * argv[]) {
    int i;
    struct hostent *host;
    if (argc != 3) {
        printf("Usage: %s <addr> \n", argv[0]);
        exit(1);
    }
    //域名转IP
    host = gethostbyname("www.baidu.com");
    if(!host)
        error_handling("gethost ... error");
    //官方域名
    printf("Official name: %s \n", host->h_name);
    //其它域名(同一IP可以对应多个域名)
    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");
    //IP地址(同一域名可以对应多个IP,负载均衡)
    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;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}




利用IP地址获取域名(有时一些IP获取返回NULL,可能因为路由等问题。。。做了限制。。。)

struct hostent * gethostbyaddr(const char *addr, socklen_t len, int familly);

成功时返回hostent结构体变量地址值,失败时返回NULL指针

实例代码:

//
//  main.cpp
//  hello_client
//
//  Created by app05 on 15-8-12.
//  Copyright (c) 2015年 app05. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>

void error_handling(char *message);

int main(int argc, const char * argv[]) {
    int i;
    struct hostent *host;
    struct sockaddr_in addr;
    if (argc != 3) {
        printf("Usage: %s <addr> \n", argv[0]);
        exit(1);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_addr.s_addr = inet_addr("216.58.221.36");
    //IP转域名
    host = gethostbyaddr((char *) &addr.sin_addr, 4, AF_INET);
    if(!host)
        error_handling("gethost ... error");
    //官方域名
    printf("Official name: %s \n", host->h_name);
    //其它域名(同一IP可以对应多个域名)
    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");
    //IP地址(同一域名可以对应多个IP,负载均衡)
    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;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}




扩展:上面两个转换函数的很多参数或返回值结构体中地址信息都定义为(char*)类型,而不是直接in_addr类型。是因为这两个函数不光是为IPv4设定的,还可以是IPv6。因此,考虑通用性,声明类型为char指针类型的数组。其实,对于指针所指对象不明确时,使用(void *)类型更合理,只是因为当时定义这些函数时,void指针标准还没出来。

struct in_addr

{

In_addr_t s_addr; //4字节IPv4地址

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: