UNP总结 Chapter 11 名字与地址转换
本章讲述在名字和数值地址间进行转换的函数: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 <netdb.h> 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设置为定义在头文件<netdb.h>中的下列常值中的一个:
- HOST_NOT_FOUND
- TRY_AGAIN
- NO_RECOVERTY
- NO_DATA(等同于NO_ADDRESS)
3.gethostbyaddr函数
gethostbyaddr函数试图有一个二进制的IP地址找到相应的主机名,与gethostbyname函数行为刚好相反
#include <netdb.h> 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 <netdb.h> 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 <netdb.h> 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 <netdb.h> int getaddrinfo (const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result) ;
//返回:若成功为0,出错为非0(见后图11-7)
hostname参数是一个主机名或地址串,service参数是一个服务名或十进制端口字串,
本函数通过result指针参数返回一个指向addrinfo结构链表的指针,而addrinfo结构定义在头文件<netdb.h>
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 <netdb.h> const char *gai_strerror (int error);
//返回错误描述消息字符串的指针
7.freeaddrinfo函数
函数getaddrinfo返回的所有存储空间通过调用freeaddrinfo返还给系统
#include <netdb.h> void freeaddrinfo (struct addrinfo *ai);
ai应指向getaddrinfo返回的第一个addrinfo结构。在该链表中的所有结构,以及这些机构所指向的动态存储空间都将被释放。
只复制addrinfo结构,而不复制addrinfo结构所指向的其他结构,叫做浅拷贝或浅复制(shallow copy)。复制addrinfo结构,同时复制addrinfo结构所指向的其他结构,称为深拷贝或深复制(deep copy)。
8.getnameinfo函数
getnameinfo函数与getaddrinfo互补:它以一个套接口地址为参数,返回一个描述主机的字符串和一个描述服务的字符串。这个函数以一种独立于协议的方式提供这些信息
#include <netdb.h> 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 = 1;
struct addrinfo hints, *res, *ressave; bzero(&hints, sizeof (struct addrinfo)) ;
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; if ( (n = getaddrinfo (host, serv, &hints, &res)) != 0)
err_quit("tcp_listen error for %s, %s: %s",
host, serv, gai_strerror(n)) ;
ressave = res; do {
listenfd =
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) == 0)
break; /* success */
Close (listenfd); /* bind error, close and try next one */
} while ( (res = res->ai_next) != NULL);
if (res == NULL) /* errno from final socket () or bind () */
err_sys ("tcp_listen error for %s, %s", host, serv);
Listen (listenfd, LISTENQ);
if (addrlenp)
*addrlenp = res->ai_addrlen; /* return size of protocol address */
freeaddrinfo (ressave);
return (listenfd);
}
UNP总结 Chapter 11 名字与地址转换的更多相关文章
- 《Unix 网络编程》11:名字和地址转换
名字和地址转换 系列文章导航:<Unix 网络编程>笔记 域名系统 简介 域名系统主要用于主机名字和 IP 地址之间的映射.主机名可以是: 简单名字,如:centos01 全限定域名(FQ ...
- UNP第11章——名字与地址转换
1.域名系统 程序中只使用主机名和服务名的好处是,如果IP或端口变化,只需要改变映射关系,不需要重新编译程序. 1.1 资源记录 DNS的条目为资源记录,有用的项如下: A IPv4地址 AAAA I ...
- UNP学习笔记(第十一章 名字与地址转换)
域名系统 域名系统(Domain Name System,DNS)主要用于主机名字与IP地址之间的映射. 主机名既可以是一个简单得名字,如solaris,也可以是一个全限定域名,如solaris.un ...
- UNIX网络编程读书笔记:名字与地址转换
概述 在名字和数值地址间进行转换的函数: gethostbyname和gethostbyaddr:在主机名字与IPv4地址之间进行转换.仅仅支持IPv4. getservbyname和getservb ...
- UNP学习第九章 基本名字与地址转换
之前都用数值地址来表示主机(206.6.226.33),用数值端口号来标识服务器. 然而,我们应该使用名字而不是数值:名字比较容易记,数值地址可以改变但名字保持不变. 随着往IPv6上转移,数值地址变 ...
- UNIX网络编程——名字与地址转换(gethostbyname,gethostbyaddr,getservbyname,getservbyport,getaddrinfo,getnameinfo函数)
名字和数值地址间进行转换的函数:gethostbyname和gethostbyaddr在主机名字与IPv4地址之间进行转换.getservbyname和getservbyport在服务器名字和端口号之 ...
- socket概述和字节序、地址转换函数
一.什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口. socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信. socket API是一层抽象的网 ...
- NAT(地址转换技术)详解
目录 NAT产生背景ip地址基础知识NAT技术的工作原理和特点静态NAT动态NATNAT重载(经常应用到实际中)NAT技术的优缺点优点缺点NAT穿越技术应用层网关(ALG)ALG的实际应用NAT技术的 ...
- [转]字符型IP地址转换成数字IP的SQL函数
使用SQL函数可以实现许多的功能,下面为您介绍的是字符型IP地址转换成数字IP的SQL函数示例,供您参考,希望对您学习SQL函数能够有所帮助. /**//*--调用示例 sele ...
随机推荐
- Free Pascal 的安装
Free Pascal 的安装 https://www.cnblogs.com/cnssc/p/6110492.html https://wenku.baidu.com/view/ee80cc8eed ...
- jquery获取<div></div>之间的内容.text() 和 .html()区别
jQuery 获取 div 之间的内容,有两种方法,$(selector).text().$(selector).html() . html: <div> <p>test< ...
- cas单点登录 deployerConfigContext.xml正确配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- hdu1034 简单模拟
这里开一个二维数组.num[105][2]; 我也不知道N有多少,随便开的, 那么这里num[i][0] 表示当前 第 i 个人拥有的糖果数,num[i][1]表示他上面一个人分给他的糖果数.详 ...
- xammp 配置虚拟主机
## This is the main Apache HTTP server configuration file. It contains the# configuration directives ...
- 验证loadrunner对Ajax内容的校验
前一阵和开发的同事一起測试某个系统的性能.此系统是发送Ajax请求到后台,再调用第三方的某项服务. 第三方服务的性能由不得我们控制.因此开发者做了一下改进.超时则直接返回. 于是在loadrunner ...
- eclipse如何查问题?
问题:从SVN上拉了一个项目,莫名奇妙就报错?看着就很纠结 解决之道:在Window下拉菜单show View 找到Problems 就可以查到具体的原因,我的这个是需要添加一个tomcat服务器
- C# 通过Hook的方法 屏蔽快捷键
#region 屏蔽Windows功能键(快捷键) public delegate int HookProc(int nCode, int wParam, IntPtr lParam ...
- 简述C++中的多态机制
前言 封装性,继承性,多态性是面向对象语言的三大特性.其中封装,继承好理解,而多态的概念让许多初学者感到困惑.本文将讲述C++中多态的概念以及多态的实现机制. 什么是多态? 多态就是多种形态,就是许多 ...
- 【windows phone】CollectionViewSource的妙用
在windows phone中绑定集合数据的时候,有时候需要分层数据,通常需要以主从试图形式显示.通常的方法是将第二个ListBox(主视图)的数据源绑定到第一个ListBox (从视图)的Selec ...