热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

UNP总结Chapter11名字与地址转换

本章讲述在名字和数值地址间进行转换的函数:gethostbyname和gethostbyaddr在主机名字与IP地址间进行转换,getservbynam

本章讲述在名字和数值地址间进行转换的函数:gethostbyname和gethostbyaddr在主机名字与IP地址间进行转换,getservbyname和getservbyport在服务器名字和端口号间进行转换

 

1.域名系统

域名系统(Domain Name System,DNS)主要用于主机名与IP地址间的映射。主机名可以是简单名字,如solaris或bsdi,也可以是全限定域名FQDN(Fully Qualified Domain Name),如solaris.kohala.com

1).资源记录

DNS中的条目称为资源记录RR(resource record),一般感兴趣的有如下几个:

  • A           A记录将主机名映射为32位的IPv4地址。
  • AAAA     AAAA记录将主机名映射为128位的IPv6地址。
  • PTR        PTR记录(称为"指针记录")将IP地址映射为主机名。对于IPv4地址,32位地址的四个字节顺序反转,每个字节都转换成他的十进制ASCII值(0~255),然后附上in-addr.arpa,结果串用于PTR查询。对于IPv6地址,128位地址中的32个4位组顺序发转,每组被转换成相应的十六进制ASCII值(0~9, a~f),并附上ip6.int。
  • MX         MX记录指定一主机作为某主机的“邮件交换器”。
  • CNAME   CNAME代表“canonical name(规范名字)”,其常见的用法是为常用服务如ftp和www指派一个CNAME记录。

 

2).解析器和名字服务器

组织运行一个或多个名字服务器(name server), 它们通常就是所谓的BIND(Berkeley Internet Name Domain)程序。各种应用程序,如本书中我们编写的客户和服务器程序,通过调用称为解析器(resolver)的库中的函数来与DNS服务器联系。最常见的解析器函数是gethostbyname和gethostbyaddr。

 

 

 

 

2.gethostbyname函数

查找主机名最基本的函数是gethostbyname,如果调用成功,它就返回一个指向hostent的结构指针,该结构中含有所查找主机的所有IPv4地址,这个函数的局限是只能返回IPv4地址。

#include struct hostent *gethostbyname (const char *hostname);
//返回:若成功为非空指针,出错为NULL其设置h_error

本函数返回的空指针指向如下的hostent结构

struct hostent {char *h_name; /* official (canonical) name of host */char **h_aliases; /* pointer to array of pointers to alias names */int h_addrtype; /* host address type: AF_INET */int h_length; /* length of address: 4 */char **h_addr_list; /* ptr to array of ptrs with IPv4 addrs */
};

按照DNS的说法,gethostbyname执行的是对A记录查询。它只能返回IPv4地址

hostent结构如下所示

gethostbyname与我们所介绍的其他套接口函数不同之处在于:当发生错误时,他不设置errno,而是将全局整数h_errno设置为定义在头文件中的下列常值中的一个:

  • HOST_NOT_FOUND
  • TRY_AGAIN
  • NO_RECOVERTY
  • NO_DATA(等同于NO_ADDRESS)

 

 

3.gethostbyaddr函数

gethostbyaddr函数试图有一个二进制的IP地址找到相应的主机名,与gethostbyname函数行为刚好相反

#include struct hostent *gethostbyaddr (const char *addr, socklen_t len, int family);
//返回:成功为空指针,出错为NULL并设置h_errno

本函数返回一个指向与之前所叙述一样的hostent结构的指针。

参数addr实际上不是char *类型,而是一个指向存放IPv4地址的某个in_addr结构的指针;len参数是这个结构的大小:地域IPv4地址为4,family参数为AF_INET

 

 

4.getservbyname和getservbyport函数

 1).像主机一样,服务也通常靠名字来认知,getservbyname函数用于根据给定名字查找相应服务,即:返回对应于给定服务名和协议名的相关服务信息(例如:端口号)

#include struct servent * getservbyname(const char * servname, const char * protoname);//返回: 非空指针-成功,空指针-出错

本函数返回的空指针指向如下的servent结构

struct servent {char *s_name; /* official service name */char **s_aliases; /* alias list */int s-port; /* port number, network-byte order */char *s_proto; /* protocol to use */
};

服务名servname必须指定,如果还指定了一个协议(即protoname为非空指针),则结果表项也必须有匹配的协议。

servent结构中我们关心的主要字段是端口号。既然端口号是以网络字节序返回的,把它存储于套接口地址结构时绝对不能调用htons,对此函数的典型调用是:

struct servent *sptr;sptr = getservbyname("domain", "udp"); /* DNS using UDP */
sptr = getservbyname("ftp", "tcp"); /* FTP using TCP */
sptr = getservbyname("ftp", NULL); /* FTP using TCP */
sptr = getservbyname("ftp", "udp"); /* this call will fail */


2).函数getservbyport用于给定端口号和可选协议查找相应服务

#include struct servent *getservbyport (int port, const char *protoname);
//返回:成功非空指针,出错为NULL

port参数的值必须为网络字节序,本函数的典型调用如下:

struct servent *sptr;sptr = getservbyport (htons (53), "udp"); /* DNS using UDP */
sptr = getservbyport (htons (21), "tcp"); /* FTP using TCP */
sptr = getservbyport (htons (21), NULL); /* FTP using TCP */
sptr = getservbyport (htons (21), "udp"); /* this call will fail */

对于UDP,由于没有服务使用端口21,所以最后一个调用将失败。

 

 

 

5.getaddrinfo函数

getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个sockaddr结构而不是一个地址列表,这些sockaddr结构随后可由套接字函数直使用

#include int getaddrinfo (const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result) ;//返回:若成功为0,出错为非0(见后图11-7)

hostname参数是一个主机名或地址串,service参数是一个服务名或十进制端口字串,

本函数通过result指针参数返回一个指向addrinfo结构链表的指针,而addrinfo结构定义在头文件

struct addrinfo {int ai_flags; /* AI_PASSIVE, AI_CANONNAME */int ai_family; /* AF_xxx */int ai_socktype; /* SOCK_xxx */int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */socklen_t ai_addrlen; /* length of ai_addr */char *ai_canonname; /* ptr to canonical name for host */struct sockaddr *ai_addr; /* ptr to socket address structure */struct addrinfo *ai_next; /* ptr to next structure in linked list */
};

同样,getaddrinfo函数的参数hints也为类型。hints参数可以的一个空指针,也可以指向addrinfo结构的指针,调用者可在这个结构中填入关于期望返回的信息类型的暗示。举例来说,如果指定的服务既支持TCP也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。

hints结构中调用者可以设置的成员有:

  • ai_flags(零个或多个或在一起的AI_xxx值)
  • ai_family(某个AF_xxx值)
  • ai_socktype(某个SOCK_xxx值)
  • ai_protocol

其中ai_flags成员可用的标志值及其含义 例如有 AI_PASSIVE(套接字将用于被动打开),AI_CANONNAME(告知getaddrinfo函数返回主机的规范名字)等等

如果本函数返回成功,那么由result参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表。可以导致返回多个addrinfo结构的情形有以下2个:

  • 如果与hostname参数关联的地址有多个,那么适用于所请求地址簇的每个地址都返回一个对应的结构。
  • 如果service参数指定的服务支持多个套接口类型,那么每个套接口类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype成员。

我们必须先分配一个hints结构,把它清零后填写需要的字段,再调用getaddrinfo然后遍历一个链表逐个尝试每个返回地址。

实例程序:

struct addrinfo hints, *res;bzero(&hints, sizeof(hints) ) ;
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;getaddrinfo("freebsd4", "domain", &hints, &res);

返回信息如下图:

 

--关于getaddrinfo如果用于IPv6,详见UNP

 

 

6.gai_strerror函数

下图给出了有getaddrinfo返回非0错误值的名字和含义

gai_strerror以这些值为它的参数,返回一个指向对应的出错信息串的指针

#include const char *gai_strerror (int error);
//返回错误描述消息字符串的指针

 

 

7.freeaddrinfo函数

函数getaddrinfo返回的所有存储空间通过调用freeaddrinfo返还给系统

#include void freeaddrinfo (struct addrinfo *ai);

ai应指向getaddrinfo返回的第一个addrinfo结构。在该链表中的所有结构,以及这些机构所指向的动态存储空间都将被释放。

只复制addrinfo结构,而不复制addrinfo结构所指向的其他结构,叫做浅拷贝或浅复制(shallow copy)。复制addrinfo结构,同时复制addrinfo结构所指向的其他结构,称为深拷贝或深复制(deep copy)。

 

8.getnameinfo函数

getnameinfo函数与getaddrinfo互补:它以一个套接口地址为参数,返回一个描述主机的字符串和一个描述服务的字符串。这个函数以一种独立于协议的方式提供这些信息

#include int getnameinfo (const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen,
char *serv, socklen_t servlen, int flags) ;
//成功为0,出错为非0(如gai_strerror函数中的表)

sockaddr指向包含协议地址的套接口地址结构,它将会被转换成可读的字符串,addrlen是结构的长度。这个结构和长度通常由accept, recvfrom, getsockname,getpeername返回

待返回的2个直观可读字符串由调用者预先分配存储空间,host和hostlen指定主机字串,serv和servlen指定服务字串。如果调用者不想返回主机字串或者服务字串,那就指定hostlen或者servlen为0.

sock_ntop和getnameinfo的差别在于,前者不涉及DNS,直接返回可输出的IP地址和端口号,后者通常试图给主机和服务的名字。

 

 

9.关于getaddrinfo的例子

这里仅给出tcp_listen函数,其余详见UNP

#include "unp.h"int
tcp_listen(const char *host, const char *serv, socklen_t *addrlenp)
{int listenfd, n;const int on &#61; 1;struct addrinfo hints, *res, *ressave;bzero(&hints, sizeof (struct addrinfo)) ;hints.ai_flags &#61; AI_PASSIVE;hints.ai_family &#61; AF_UNSPEC;hints.ai_socktype &#61; SOCK_STREAM;if ( (n &#61; getaddrinfo (host, serv, &hints, &res)) !&#61; 0)err_quit("tcp_listen error for %s, %s: %s",host, serv, gai_strerror(n)) ;ressave &#61; res;do {listenfd &#61;socket(res->ai_family, res->ai_socktype, res->ai_protocol);if (listenfd <0)continue; /* error, try next one */Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on) ) ;if (bind(listenfd, res->ai_addr, res->ai_addrlen) &#61;&#61; 0)break; /* success */Close (listenfd); /* bind error, close and try next one */} while ( (res &#61; res->ai_next) !&#61; NULL);if (res &#61;&#61; NULL) /* errno from final socket () or bind () */err_sys ("tcp_listen error for %s, %s", host, serv);Listen (listenfd, LISTENQ);if (addrlenp)*addrlenp &#61; res->ai_addrlen; /* return size of protocol address */freeaddrinfo (ressave);return (listenfd);
}

 



推荐阅读
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 体积小巧的vsftpd与pureftpd Docker镜像在Unraid系统中的详细配置指南:支持TLS加密及IPv6协议
    本文详细介绍了如何在Unraid系统中配置体积小巧的vsftpd和Pure-FTPd Docker镜像,以支持TLS加密和IPv6协议。通过这些配置,用户可以实现安全、高效的文件传输服务,适用于各种网络环境。配置过程包括镜像的选择、环境变量的设置以及必要的安全措施,确保了系统的稳定性和数据的安全性。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
  • 在IIS上运行的WebApi应用程序在开发环境中能够正常进行文件的读写操作。然而,在尝试通过FTP访问实时服务器上的文件列表时,遇到了无法显示的问题,尽管服务器配置与开发环境相同。这可能涉及权限设置、FTP服务配置或网络连接等方面的问题。 ... [详细]
  • 2016-2017学年《网络安全实战》第三次作业
    2016-2017学年《网络安全实战》第三次作业总结了教材中关于网络信息收集技术的内容。本章主要探讨了网络踩点、网络扫描和网络查点三个关键步骤。其中,网络踩点旨在通过公开渠道收集目标信息,为后续的安全测试奠定基础,而不涉及实际的入侵行为。 ... [详细]
  • 安装 IIS 5.1 并注册 .NET 2.0 后,访问页面时出现 500 错误。本文提供详细的步骤和解决方案,帮助您解决该问题。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 解决Only fullscreen opaque activities can request orientation错误的方法
    本文介绍了在使用PictureSelectorLight第三方框架时遇到的Only fullscreen opaque activities can request orientation错误,并提供了一种有效的解决方案。 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 深入解析 OpenSSL 生成 SM2 证书:非对称加密技术与数字证书、数字签名的关联分析
    本文深入探讨了 OpenSSL 在生成 SM2 证书过程中的技术细节,重点分析了非对称加密技术在数字证书和数字签名中的应用。非对称加密通过使用公钥和私钥对数据进行加解密,确保了信息传输的安全性。公钥可以公开分发,用于加密数据或验证签名,而私钥则需严格保密,用于解密数据或生成签名。文章详细介绍了 OpenSSL 如何利用这些原理生成 SM2 证书,并讨论了其在实际应用中的安全性和有效性。 ... [详细]
  • 在CentOS系统中部署与配置ZooKeeper详解 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 在网络故障排查中,tcpdump 是一款强大的工具,尤其在 Linux 环境下。尽管开发环境中问题较少,但在测试或生产环境中,往往会遇到各种难以预料的异常情况。通过在问题发生的环境中启用 tcpdump 进行抓包,并重现问题,可以获取到宝贵的原始数据,为问题的诊断提供关键线索。本文将详细介绍如何使用 tcpdump 进行实战操作,帮助读者掌握这一技能。 ... [详细]
author-avatar
上海千恩万燮
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有