域名系统

DNS是对IP地址和域名进行互相转换的系统,其核心是DNS服务器。提供网络服务的服务端也是通过IP地址来区分的,但由于IP地址难于记忆,因此通过容易记忆并表述的域名来取代IP地址

在浏览器地址栏输入www.baidu.com,或如图1-1用ping命令获取其IP地址,便可访问百度主页,那么通用域名访问和通过IP访问这二者有何区别?

图1-1   用ping命令获取百度地址

实际上,域名是赋予服务端的虚拟地址,而非实际地址。因此需要将虚拟地址转化为实际地址。那么,如何将域名转化为IP地址呢?DNS服务器承担此重任,可以向DNS服务器请求转换地址。所有计算机中都记录着默认DNS服务器地址,就是通过默认DNS服务器得到相应域名的IP地址信息。在浏览器地址栏中输入域名后,浏览器通过默认DNS服务器获取该域名对应的IP地址信息,之后才真正接入该网站

计算机内置的默认DNS服务器并不知道网络上所有域名的IP地址信息,若该DNS服务器无法解析,则会询问其他DNS服务器并提供给用户,如图1-2

图1-2   DNS和请求获取IP地址信息

图1-2展示了默认DNS服务器无法解析主机询问的域名对应IP地址时的应答过程,可以看出,默认DNS服务器收到自己无法解析的请求时,向上级DNS服务器询问,通过这种方式逐级向上传递信息,到达顶级DNS服务器时——根DNS服务器,它知道该向哪个DNS服务器询问,向下级DNS传递解析请求,得到IP地址后原路返回,最终将解析的IP地址传递到发起请求的主机,DNS就是这样层次化管理的一种分布式数据库系统

利用域名获取IP地址

#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);//成功时返回hostent结构体指针,失败时返回NULL指针

  

只要向这个函数传递域名字符串,就会返回域名所对应的IP地址。只是返回时,地址信息装入hostent结构体,此结构体定义如下:

struct hostent
{char *h_name;         //正式主机名char **h_aliases;     //主机别名int h_addrtype;       //主机IP地址类型:IPV4-AF_INETint h_length;       //主机IP地址字节长度,对于IPv4是四字节,即32位char **h_addr_list;   //主机的IP地址列表
};

  

从上述结构体可以看出,当调用gethostbyname函数时不止返回IP信息,同时还带着其他信息,下面简要介绍下上述结构体中的各个成员:

  • h_name:该变量存有官方域名,官方域名代表某一主页,但实际上,一些著名公司的域名并未使用官方域名注册
  • h_aliases:可以通过多个域名访问同一主页,同一IP可以绑定多个域名,因此,除官方域名外还可指定其他域名
  • 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地址信息

调用gethostbyname函数后返回的hostent结构体变量结构如图1-3所示:

图1-3   hostent结构体变量

下面我们看一下gethostbyname函数的应用,并说明hostent结构体变量的特性

gethostbyname.c

#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, 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("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;
}
void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

  

  • 第17行:通过main函数传递的字符串作为参数传给gethostbyname函数
  • 第20行:输出官方域名
  • 第21、22行:输出除官方域名以外的域名
  • 第24、25行:输出IP地址信息

编译gethostbyname.c并运行

# gcc gethostbyname.c -o gethostbyname
# ./gethostbyname www.taobao.com
Official name:www.taobao.com.danuoyi.tbcache.com
Aliases 1:www.taobao.com
Address type:AF_INET
IP addr 1:61.154.126.109
IP addr 2:218.67.61.254

  

大家可在编译gethostbyname.c后自行选择一个域名进行测试,现在我们看一下第24和25行,如果我们只看hostent结构体的定义,结构体成员h_addr_list指向了一个字符串指针数组(由多个字符串地址构成的数组)。但字符串指针数组中的元素实际指向的是in_addr结构体地址而非字符串,如图1-4所示:

图1-4   h_addr_list结构体成员

图1-4给出了h_addr_list结构体的参照关系,正因如此,上述代码中才有了第25行的类型转换,并调用inet_ntoa函数

这里可能大家会有疑问,为什么是char *而不是in_addr *?hostent结构体的成员h_addr_list指向的数组类型并不是in_addr结构体的指针数组,而是采用了char指针。是因为hostent结构体并非只为IPv4准备,因此考虑到通用性,声明为char指针类型的数组。那么,声明为void指针类型的数组是否更合理?确实,如果指针对象不明确时,声明为void指针类型更合理,但我们所学习的套接字函数是早在void指针标准化之前定义的,在当时无法确定指针类型时都采用char指针

利用IP地址获取域名

之前介绍的gethostbyname函数利用域名获取包括IP地址在内的域相关信息,而gethostbyaddr函数利用IP地址获取域相关信息

#include <sys/socket.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

现在我们来看一下gethostbyaddr函数的使用方法

gethostbyaddr.c

#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, char *argv[])
{int i;struct hostent *host;struct sockaddr_in addr;if (argc != 2){printf("Usage : %s <IP>\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;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

  

除第22行的gethostbyaddr函数调用外,与gethostbyname.c并无区别,因为函数调用的结果是通过hostent结构体变量地址值传递的

编译gethostbyaddr.c并运行

# gcc gethostbyaddr.c -o gethostbyaddr
# ./gethostbyaddr 218.67.61.254
Official name: 254.61.67.218.broad.sm.fj.dynamic.163data.com.cn
Address type: AF_INET
IP addr 1: 218.67.61.254

  

之前我们通过gethostbyname.c获得了某宝的IP地址,现在我们尝试用之前获得的IP地址反过来获取域名信息。从运行结果可以看到,记录于DNS的官方主页地址具有特殊格式

转载于:https://www.cnblogs.com/beiluowuzheng/p/9684656.html

TCP/IP网络编程之域名及网络地址相关推荐

  1. 网络编程+go+java,Go语言中的TCP/IP网络编程

    Go语言TCP/IP网络编程 乍一看,通过TCP/IP层连接两个进程会感觉可怕, 但是在Go语言中可能比你想象的要简单的多. TCP/IP层发送数据的应用场景 当然很多情况下,不是大多数情况下,使用更 ...

  2. TCP/IP网络编程(一)

    TCP/IP网络编程读书笔记 第1章 理解网络编程和套接字 1.1 理解网络编程和套接字 1.1.1 构建打电话套接字 1.1.2 编写 Hello World 套接字程序 1.2 基于Linux的文 ...

  3. 《TCP/IP 网络编程》笔记

    本文主要基于<TCP/IP 网络编程>这本书进行总结,主要针对 Linux 网络编程部分进行阐述,Windows 网络编程部分有需要建议阅读原书籍. 一.基础知识 网络编程 网络编程就是编 ...

  4. TCP/IP网络编程---Linux系统下的TCP套接字编程

    目录 第一章 理解网络编程和套接字 1.1 网络编程和套接字概要 1.2 基于Linux的文件操作 1.2.1 底层文件访问和文件描述符 1.2.2 打开文件 1.2.3 关闭文件 1.2.4 将数据 ...

  5. TCP/IP网络编程:P3->地址族与数据序列

    本系列文章为<TCP/IP网络编程----尹圣雨>学习笔记,前面的系列文章链接如下 TCP/IP网络编程:P1->理解网络编程和套接字 TCP/IP网络编程:P2->套接字类型 ...

  6. 高等学校计算机科学与技术教材:tcp/ip网络编程技术基础,TCP/IP网络编程技术基础...

    TCP/IP网络编程技术基础 语音 编辑 锁定 讨论 上传视频 <TCP/IP网络编程技术基础>是2012年北京交通大学出版社出版的图书,作者是王雷. 书    名 TCP/IP网络编程技 ...

  7. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

  8. TCP/IP网络编程(3)

    基于DUP的服务端与客户端 在TCP/IP网络编程(2)中,介绍了TCP/IP的四层模型,传输层分为TCP和UDP两种方式,通过TCP套接字完成数据交换已经进行了介绍,下面介绍通过UDP套接字完成数据 ...

  9. TCP/IP网络编程(1)

    1. 套接字 套接字是由操作系统提供的网络数据通信软件设备,即使对网络数据传输原理不了解,也能够使用套接字完成网络数据传输.为了与远程计算机进行数据传输,需要连接到英特网,套接字就是进行网络连接的工具 ...

最新文章

  1. Python集成网络诊断小工具(含有ping,tracert,tcping等小工具)
  2. 向量图兼容组件VectorCompat
  3. java apache fileutil_Java FileUtil.listFiles方法代码示例
  4. Spring 的IOC容器系列的设计与实现:BeanFactory 和 ApplicationContext
  5. Video4Linux
  6. c语言变量ppt,C语言程序设计-变量.ppt
  7. loadrunner中对https证书的配置
  8. Codeigniter 3 拓展HMVC
  9. 读取bmp格式数据--实践思考
  10. 删除链表的中间节点 Java实现_【链表问题】删除单链表的中间节点
  11. python gil锁_python--GIL锁
  12. Tomcat配置Basic认证方案(一)
  13. [HDU3756]Dome of Circus
  14. 三星显示器 测试软件,3D+TV+APP!三星27英寸LED显示器全国首测
  15. GhostXP_SP3雨林木风纯净版Y7.0(09年12月更新版) 【雪豹】
  16. POJ - 1625 Censored!
  17. 水下传感器网络研究——第5章 路由协议
  18. 京东技术体系员工级别划分及薪资区间
  19. 9月26日-计算机导论-课程内容(3)
  20. 【Docker】9、Docker-Compose安装轻量级分布式日志服务Graylog

热门文章

  1. dhcp服务器批量修改ip租期,dhcp服务器的ip地址租期默认是多久
  2. 计算机关闭后剪切板的内容会消失,关闭计算机电源后剪贴板的信息为什么会丢失...
  3. android room数据库embed,Android room数据库基操
  4. android标签循环,iOS和Android规范解析——标签导航和分段控件
  5. c++ 调用python_闲话python 48: C/C++扩展Python与Swig工具
  6. IP地址的分类和层次
  7. 可重组合与不相邻组合
  8. bzoj 1626: [Usaco2007 Dec]Building Roads 修建道路(最小生成树)
  9. jQuery Mobile中面板panel的data-*选项
  10. 使用help()输入keywords查看python中定义的关键字