




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第6章 名字与地址转换编程,知识点: 域名系统作用 域名系统对应记录 从域名解析对应IP 从IP解析对应域名,现在的网络都是使用名字来访问服务器的,而不是使用地址来访问。 那它们是怎么转换的呢?答案就是利用名字与地址的转换函数实现的:gethostbyname和gethostbyaddr在主机名字与IP地址间进行转换,getservbyname和getservbyport在服务名字和端口号间进行转换,并且还要介绍两个与协议无关的getaddrinfo和getnameinfo函数,域名系统就是通常所说的DNS(Domain Name System)系统,而DNS系统主要用于主机名与IP地址间的映
2、射,同时还可以通过主机名或主机地址获取主机的相关信息。 那么在DNS系统中是怎样实现主机名与IP地址间的映射的呢?答案就是通过资源记录来实现。在DNS中的条目称为资源记录RR(Resource Record),它们主要有以下几类:,(1)A。A记录将一个域名地址对应一个2bit的IPv4地址。 (2)AAAA。AAAA记录(称为“四A”记录)将主机名映射为128位的IPv6地址。 (3)NS。NS记录用于指定一个域名服务器,它负责定义由哪个域名服务器负责管理维护本区域的记录。 (4)MXMX记录用于指定一台主机的域名,所有发送到本域的电子邮件都由这台主机接收。 (5)PTR。PTR记录(称为“
3、指针记录”)将IP地址映射为主机名。 (6)CNAME。CNAME代表Canonical Name(规范名字),作用是允许主机建立别名。,gethostbyname()函数,找主机名最基本的函数gethostbyname(),该函数执行如果成功,它返回一个指向结构hostent的指针,该结构中包含了该主机的所有IPv4地址或IPv6地址;如果失败返回空指针。,# include struct hostent * gethostbyname (const char * hostname); 参数hostname是主机的域名地址,函数将查询的结果作为参数返回。如果失败返回空指针;如果成功此参数返回
4、的非空指针指向如下的hostent结构:,struct hostent char * h_name;/*主机的正式名称*/ char * * h_aliases;/*主机的别名列表*/ inth_addrtype;/*主机地址类型*/ inth_length;/*主机地址长度*/ char * * h_addr_list;*主机IP地址的列表*/ ; # define h_addr h_addr_list0/*在列表中的第一个地址*/,gethostbyname()函数是怎样工作的,原来gethostbyname函数首先在/etc/hosts文件中查找是否有匹配的主机名。如果没有,则根据在域名
5、解析配置文件/etc/resolv.conf中指定的本地域名服务器的地址向本地域名服务器发送地址解析请求。如果本地域名服务器能够解析,则返回UDP数据包说明结果,否则本地域名服务器将向上一层的域名服务器发送域名解析请求。,下面举个例子来看看gethostbyname()函数,#include #include #include main(int argc, const char *argv) ulong_t addr; struct hostent *hp; char *p; if (argc != 2) (void) printf(usage: %s host_namen, argv0);
6、exit (1); hp = gethostbyname(argv1); if (hp = NULL) (void) printf(host information for %s not foundn, argv1); exit (2); for (p = hp-h_addr_list; *p != 0; p+) struct in_addr in; char *q; (void) memcpy( ,RES_USE_INET6解析器选项,解析器选项是用来通知解析器让gethostbyname返回的是IPv6地址而不是IPv4地址。 设置该选项的方法有以下3种: (1)应用程序可以设置此选项 (
7、2)如果环境变量RES_OPTIONS中含有串inet6,则此选项打开 (3)在配置文件中如果包含“options inet6”时选项打开,但如果这样设置了,则此选项影响主机上调用解析器函数的所有应用程序,因此这项技术要在结构hostent中返回的IPv6地址可以被主机上的所有应用程序处理时才能使用。,gethostbyname2函数对IPv6的支持,gethostbyname2()函数,该函数有两个参数,并允许指定地址族。 # include struct hostent * gethostbyname2(const char * hostname,int family) 返回:若为非空指针
8、,则表示成功;若为空指针,则表示出错,同时设置h_errno。 该函数的返回值与gethostbyname的返回值相同,为一个指向结构hostent的指针。该函数的逻辑依赖于参数family和解析器选项RES_USE_INET6,gethostbyaddr()函数,gethostbyaddr()函数的作用是可以查询指定的IP地址对应的主机域名地址。函数的形式如下: # include struct hostent * gethostbyaddr(const char * addr, size_t len , int family ); 返回:若为非空指针,则表示成功;若为空指针,则表示出错,同
9、时设置h_errno。 该函数同样返回一个指向结构hostent的指针。而在参数中,参数addr不是char *类型,而是一个真正指向含有IPv4或IPv6地址的结构in_addr或in6_addr的指针;len是此结构的大小,对于IPv4地址为4,对于IPv6地址为16;参数family为AF_INET或AF_INET6。,uname()函数,该函数功能如同它的名字一样,即返回当前主机的名字,它返回的信息比较完整。下一节将介绍返回主机名字的另一个函数,但它返回的信息就相对少些。 经常与函数gethostbyname()一起用来确定本地主机的IP地址。它的具体形式如下: # include i
10、nt uname (struct utsname * name); 返回:若为非负值,则表示成功;若为-1,则表示出错。,gethostname函数,该函数同样返回当前主机的名字,但返回信息比上节介绍的函数少,该函数形式如下: # include intgethostname(char * name , size_t namelen); 返回:若为0,则表示成功;若为-1,则表示出错。 name是指向主机名存储位置的指针,namelen是此数组的大小。如果有空间,主机名以空字符结束。主机名的最大长度通常是由头文件定义的常值MAXHOSTNAMELEN。,getservbyname和getser
11、vbyport函数,函数getservbyname()可以通过服务名来获取服务器端口号,函数的形式如下: # include struct servent * getservbyname (const char * servname, const char * protoname); 返回:若为非空指针,则表示成功;若为空指针,则表示出错。,函数是getservbyport()函数,该函数的作用是通过端口号来获取服务名,它是反向的查询服务名称,即功能与getservbyname()函数相反。下面就来看一下它的具体形式: # include struct servent *getservbypo
12、rt (int port , const char *protname); 返回:若为非空指针,则表示成功;若为空指针,则表示出错。,getaddrinfo、gai_strerror和host_serv函数,getaddrinfo()函数在库函数中隐藏了所有协议依赖性,因此应用程序只需要处理由getaddrinfo填写的套接口地址结构即可。该函数的形式如下: # include int getaddrinfo (const char * hostname, const char *service, const struct addrinfo * hints, struct addrinfo *
13、 * result); 返回:若成功返回0,若出错返回非0。,gai_strerror()函数,该函数返回的非零错误值的名字和含义如表6-2所示。gai_strerror()函数以这些值作为它的一个参数,返回指向对应的出错信息字符串的指针。该函数形式如下: #include char * gai_strerror (int error ); 返回:一个指向描述出错信息字符串的指针。,填写hints结构的函数,即host_serv()函数,它以地址族和套接口类型作为参数,形式如下: # include unp.h struct addrinfo *host_serv (const char *
14、hostname, const char * service, int family, int socktype); 返回:若成功返回指向addrinfo结构的指针,若出错返回NULL。,freeaddrinfo函数,getaddrinfo()函数返回的存储空间,包括addrinfo结构、ai_addr结构和ai_canonname字符串,都是用malloc动态获取的。这些空间可调用freeadddrinfo()函数释放。下面就来看一下这个函数。 # include void freeaddrinfo (struct addrinfo * ai); 该函数的参数ai指向getaddrinfo返
15、回的第一个addrinfo结构,因此该链表中的所有结构和这些结构所指向的动态存储空间都将被释放。这样可以通过它来回收资源,同时如果在getaddrinfo()函数中调用某个操作时失败,也可以调用freeaddrinfo()函数来对错误进行处理。,使用getaddrinfo的TCP和UDP,有了host_serv()函数后,现在来看一下getaddrinfo在TCP中的应用,先从tcp_connect()函数着手,该函数执行客户程序的一般操作步骤是:创建一个TCP套接口并与服务器建立连接,它的形式如下: # include unp.h int tcp_connect (const char *
16、hostname, const char * servi ce ); 返回:若成功则返回已连接套接口的描述字,若出错则不返回。,#include unp.h int tcp_connect(const char *host, const char *serv) int sockfd, n; struct addrinfo hints, *res, *ressave; bzero( ,当用此函数时如果getaddrinfo()失败,或所有connect()失败,这个函数(以及在以下描述的给getaddrinfo()提供一些简单接口的其他函数)将终止。只有在成功时这个函数才返回。 接下来看一下另一
17、个函数tcp_listen(),它是用来执行TCP服务器程序的一般操作步骤,即创建一个TCP套接口,给它捆绑服务器的众所周知端口,并允许接收外来的连接请求,该函数形式如下:,# include unpH int tcp_listen (const char * hostname, const char * service, socklen_t * lenptr); 返回:若成功返回已连接套接口描述字,若出错则不返回。,#include unp.h int tcp_listen(const char *host, const char *serv, socklen_t *addrlenp) in
18、t listenfd, n; const int on = 1; struct addrinfohints, *res, *ressave; bzero( ,到现在为止,已用以上两个函数的源码介绍了getaddrinfo()函数在TCP中的一些应用,这将对理解getaddrinfo()函数有很大的帮助,但是这是在TCP中的应用,那么在UDP中又是怎样的情况呢?同样分别通过udp_client()、udp_connect()、udp_server()三个函数来解答这个问题。 因为提供了一个创建未连接UDP套接口的客户函数给getaddrinfo(),所以在UDP中getaddrinfo()函数的
19、应用有所改变。而另一个函数udp_connect()则提供一个创建已连接UDP的套接口。 首先来看一下udp_client()函数,该函数的作用是创建一个未连接UDP套接口,返回3项数据:第一,返回值是套接口描述字;第二,saptr是一个指向套接口地址结构(由udp_client动态分配)的指针(由调用者声明)的地址,在这个结构中存放目的IP地址和端口号,用来调用sendto(),套接口地址结构的大小在1enp指向的变量中返回;最后一个参数不能是空指针(tcp_listen的最后一个参数是允许的),因为套接口地址结构的长度在调用函数sendto()和recvfrom()时都是需要的,该函数的形
20、式如下:,# include unp.h int udp_client (const char * hostname , const char * service , void * * saptr, socklen_t * lenp); 返回:若成功返回未连接套接口的描述字,若出错则不返回。,#include unp.h int udp_client(const char *host, const char *serv, void *saptr, socklen_t *lenp) int sockfd, n; struct addrinfohints, *res, *ressave; bzer
21、o( ,接下来看一下udp_connect()函数,该函数创建一个已连接UDP套接口,该函数形式如下: # include unp.h int udp_connect (const char * hostname , const char *service); 返回:如果成功则返回套接口描述字,若出错则不返回。 当得到已连接UDP套接口后,在udp_client()函数中所需的后两个参数就不再需要了。用户可以用write函数代替sendto函数,于是就不再需要返回套接口地址结构和它的长度了。,int udp_connect(const char *host, const char *serv) int sockfd, n; struct addrinfo hints, *res, *ressave; bzero( ,这个函数与tcp_connect()几乎一样。但是有一点不同,调用在UDP套接口上的connect()不会向对方发送任何数据报。如果有错误(如对方不可达或在指定端口上没有服务器),
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论