网络编程--名字与地址转换

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)
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>

int main(int argc,char* argv[]){

    if(argc<2){
        printf("Usage:./client hostname\n");
        return -1;
    }
    struct hostent *ht=NULL;
    ht=gethostbyname(argv[1]);
    if(ht){
        int i=0;
        printf("get the host:%s addr\n",argv[1]);
        printf("name:%s\n",ht->h_name);

        printf("type:%s\n",ht->h_addrtype==AF_INET?"AF_INET":"AF_INET6");
        printf("length:%d\n",ht->h_length);

        for(i=0;;i++){
            if(ht->h_addr_list[i]!=NULL){
                printf("IP:%s\n",inet_ntoa((unsigned int *)ht->h_addr_list[i]));
            }else{
                break;
            }
        }

        for(i=0;;i++){
            if(ht->h_aliases[i]!=NULL){
                printf("alisa %d:%s\n",i,ht->h_aliases[i]);
            }else{
                break;
            }
        }
    }
    return 0;
}
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用于给定端口号和可选协议查找相应服务
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,所以最后一个调用将失败。

 

posted @ 2017-03-23 23:36  tla001  阅读(337)  评论(0编辑  收藏  举报
个人网站 www.tla001.cn