《unix网络编程》(20)名字与地址转换函数

域名系统(Domain Name System, DNS)主要用于主机名字与IP地址之间的映射。

gethostbyname / gethostbyaddr函数

通过计算机主机名字来查找。如果查找成功,返回的指向hostent结构的指针,该结构包含所查找主机的所有IPv4地址。这个函数局限于返回IPv4地址

#include <netdb.h>
#include <sys/socket.h>
struct hostent *gethostbyname(const char *name);  //函数调用失败,将返回NULL

<span class="Code">struct hostent {
     char *h_name;
     char **h_aliases;
     int h_addrtype;
     int h_length;
     char **h_addr_list;
};</span>

参数:

        char *h_name 表示的是主机的规范名。例如www.google.com的规范名其实是www.l.google.com
       char **h_aliases 表示的是主机的别名。www.google.com就是google他自己的别名。有的时候,有的主机可能有好几个别名,这些,其实都是为了易于用户记忆而为自己的网站多取的名字。
       int h_addrtype 表示的是主机ip地址的类型,到底是ipv4(AF_INET),还是ipv6(AF_INET6)
       int h_length 表示的是主机ip地址的长度
       int **h_addr_lisst 表示的是主机的ip地址,注意,这个是以网络字节序存储的。千万不要直接用printf带%s参数来打这个东西,会有问题的哇。所以到真正需要打印出这个IP的话,需要调用inet_ntop()。


gethostbyaddr函数试图由一个二进制的IP地址找到相应的主机名

#include <netdb.h>
struct hostent *gethostbyaddr(const char *addr, socklen_t len, int family);

getservbyname / getservbyport函数

       和主机一样,服务也通常靠名字来认知。如果在程序中通过其名字而不是端口号来指代一个服务,而且从名字到端口号的映射关系保存到一个文件中(通常是/etc/services),那么即使端口发生变化,只需要修改/etc/services文件中的某一行,不必重新编译应用程序。

getservbyname函数用于根据给定名字查找相应服务

#include <netdb.h>
struct  servent *getservbyname( const char *servname, const char *protoname );

struct servent {
<p> <wbr> <wbr> <wbr> <wbr> <wbr>char <wbr> <wbr> <wbr> <wbr> <wbr>*s_name; <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>// <wbr> <wbr> <wbr>服务的正是名字
 <wbr> <wbr> <wbr> <wbr> <wbr>char <wbr> <wbr> <wbr> <wbr> <wbr>**s_aliases; <wbr> <wbr> <wbr> <wbr> <wbr>// <wbr> <wbr> <wbr> 别名列表
 <wbr> <wbr> <wbr> <wbr> <wbr>int <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>s_port; <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>// <wbr> <wbr> <wbr>服务端口号
 <wbr> <wbr> <wbr> <wbr> <wbr>char <wbr> <wbr> <wbr> <wbr> <wbr>*s_proto; <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>// <wbr> <wbr> <wbr>使用的协议
};</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p>

       服务名参数servname必须指定。如果同时指定了协议(即protoname参数为非空指针),那么指定的服务必须有匹配的协议。有些因特网服务既用于TCP也用于UDP提供(如DNS)。如果protoname没有指定而servname指定服务支持多个协议,那么返回那个端口号取决于实现。一般来说,支持多个协议的服务旺旺使用相同的TCP端口号和UDP端口号。

       servent结构中关心的主要是端口号。
注意:该端口号是以网络字节的顺序返回的,因此把它存放到套接口地质结构时绝对不能调用htons。


getservbyport函数用于根据端口号和可选协议查找相应服务

#include <netdb.h>
struct  servent *getservbyport( int port, const char *protoname );

使用gethostbyname和getservbyname的例子

完整代码下载:http://download.csdn.net/download/u013074465/8621329

#include "myheader.h"

int main(int argc, char **argv) {
  int sockfd, n;
  char recvline[MAXLINE + 1];
  struct sockaddr_in servaddr;
  struct in_addr **pptr;
  struct in_addr *inetaddrp[2];
  struct in_addr inetaddr;
  struct hostent *hp;
  struct servent *sp;
  
  /*
  第一个命令行参数是主机名,我们将参数传递给gethostbyname,第二个参数
  是服务名,将它作为参数传递给getservbyname。假设使用的是TCP协议,将
  它作为getservbyname的第二个参数。如果gethostbyname失败,尝试使用inet_addr
  确定其参数是否已是ASCII格式的地址,如是则构造一个由相应的地址构成的单元素列表
  */
  if (argc != 3)
    err_exit("usage: daytimetcpcli1 <hostname> <service>");
  
  if ((hp = gethostbyname(argv[1])) == NULL) {
    if (inet_aton(argv[1], &inetaddr) == 0)
      err_exit("hostname error");
    else {
      inetaddrp[0] = &inetaddr;
      inetaddrp[1] = NULL;
      pptr = inetaddrp;
    }
  }
  else
    pptr = (struct in_addr **)hp->h_addr_list;
  
  if ((sp = getservbyname(argv[2], "tcp")) == NULL)
    err_exit("getservbyname error");
  
  /*
  对socket和connect的调用放在循环中,该循环为服务器主机的每个地址执行一次,
  直到connect成功或IP地址列表试完为止。调用socket后,我们以服务器主机IP地址
  和端口装填网际网套接字地址结构。
  */
  for (; *pptr != NULL; pptr++) {
    sockfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = sp->s_port;
    memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
    static char str[128];
    printf("trying %s\n", Inet_ntop(AF_INET, &servaddr.sin_addr, str,
sizeof(str)));
    
    if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == 0) {
      break;
    }
    err_exit("connect error");
    close(sockfd);
  }
   
  //如果循环终止的原因是没有一个connect调用成功,那就终止程序运行
  if (*pptr == NULL)
    err_exit("unable to connect");
  
  while ((n = Read(sockfd, recvline, MAXLINE)) > 0) {
    recvline[n] = 0;
    Fputs(recvline, stdout);
  }
  exit(0);
} 



getaddrinfo函数

        gethostbyname和gethostbyaddr函数仅仅支持IPv4.

        getinfoaddr函数能够处理名字到地址以及服务到端口的这两种转换,返回一个sockaddr结构而不是一个地址列表。该函数时协议无关的,它将协议相关性完全隐藏在这个库函数内部。

#include <netdb.h>
int getaddrinfo(const char *node, const char *service,
                       const struct addrinfo *hints,
                       struct addrinfo **res);
 struct addrinfo {
               int              ai_flags;
               int              ai_family;//AF_INET,AF_INET6或者AF_UNSPEC
               int              ai_socktype;//SOCK_STREAM or SOCK_DGRAM
               int              ai_protocol;//0
               size_t           ai_addrlen;//往下参数在hints中均为0或NULL
               struct sockaddr *ai_addr;
               char            *ai_canonname;
               struct addrinfo *ai_next;
};




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Unix网络编程 卷1:套接字联网API(第三版)》是由W.Richard Stevens和Bill Fenner合著的一本经典计算机网络编程图书。该书以Unix为操作系统平台,深入介绍了网络编程领域的各种概念、技术和实践。本书第三版在前两版的基础上进行了全面更新和增补,更加符合现代网络编程的需求。 该书主要内容包括了Unix套接字编程、基本I/O函数地址转换、套接字选项及协议独立性、基本UDP套接字编程、IPv6套接字编程、高级I/O函数、套接字的精确控制、Unix网络IPC、套接字选项(内外带外)以及多路复用。通过阅读该书,读者能够全面了解和掌握Unix网络编程的各个方面。 《Unix网络编程 卷1:套接字联网API(第三版)》以其全面详尽的内容、系统化的知识结构被广大计算机网络编程从业者、学生和研究者所称赞。这本书通过清晰明了的语言,配以丰富的例子和实践案例,使读者能够逐步理解并掌握网络编程领域的基础知识与实用技巧。无论是对于初学者来说,还是对于有一定网络编程基础的人士来说,本书都是一本非常有实用价值的指南。 总之,《Unix网络编程 卷1:套接字联网API(第三版)》是一本经典而全面的计算机网络编程图书,它涵盖了广泛的主题,帮助读者理解和掌握Unix网络编程的各个方面。无论是对于从事网络编程的专业人士,还是对于对网络编程感兴趣的读者来说,这本书都是一本不可或缺的参考书。 ### 回答2: 《UNIX网络编程卷1:套接字联网API(第3版)》是由W.Richard Stevens与Bill Fenner合著的一本经典的UNIX网络编程教材。这本书是学习使用UNIX套接字API进行网络编程的权威指南。 第三版的这本书是对前两版的全面更新和扩展,增加了许多新特性和最新的网络技术。它以清晰详细的文字和丰富的示例代码,深入浅出地介绍了套接字的使用,包括地址结构、套接字选项、I/O模型、多进程并发编程、进程间通信等方面的知识。 该书的结构十分有序,分为25个章节,以便于读者系统地学习和理解。每一章节都以实际应用场景和实际问题为例,通过实例向读者解释和演示套接字编程的各个方面。此外,书中还包含了大量的示例代码供读者实践和参考,加深对知识点的理解。 这本书适合那些希望深入学习UNIX套接字编程的开发人员和网络工程师。无论是在UNIX系统下进行C/S架构的网络应用开发,还是进行底层网络协议的研究和开发,都会从该书中获益匪浅。另外,该书也适合作为高校计算机相关专业的教材,供教师和学生参考和学习。 总而言之,《UNIX网络编程卷1:套接字联网API(第3版)》是一本经典且实用的UNIX网络编程教材,深入浅出地介绍了套接字编程的各个方面,对于想深入学习和应用UNIX网络编程的人士来说,是一本不可多得的参考资料。 ### 回答3: 《UNIX网络编程卷1第三版》是一本经典的计算机网络编程参考书籍,由W. Richard Stevens所著。这本书给出了关于UNIX网络编程的详细介绍和实践经验,是学习和理解UNIX网络编程的重要资料。 《UNIX网络编程卷1第三版》的PDF版本是该书的电子版,可以免费获取。通过PDF格式的书籍,读者可以在电子设备上阅读书籍内容,方便快捷。通过搜索引擎,我们可以找到相应的下载链接,然后可以将其下载到电脑或其他阅读设备上进行学习。 这本书的内容包括了UNIX网络编程的基本概念、网络编程API的使用、套接字编程、高级I/O函数名字地址转换UNIX域协议、IP版本4和版本6的网络编程等重要主题。书中详细介绍了这些主题的理论知识,并通过大量的示例代码和实践经验展示了如何应用这些知识进行网络编程。 《UNIX网络编程卷1第三版》PDF的免费获取使得这本书变得更加易于获取和传播,方便了广大读者学习和使用UNIX网络编程。无论是初学者还是有一定经验的开发者,都可以通过这本书来提升自己在网络编程领域的技能。读者可以通过系统学习和实践,逐步理解和掌握UNIX网络编程的核心概念和技术,为自己的职业发展打下良好的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值