getaddrinfo接口
getaddrinfo通过res来返回一个指向struct addrinfo结构链表的指针(注意这里返回的是一个链表),struct addrinfo结构的定义如下所示:


 
  1. struct addrinfo

  2. {

  3. int ai_flags; /* Input flags. */

  4. int ai_family; /* Protocol family for socket. */

  5. int ai_socktype; /* Socket type. */

  6. int ai_protocol; /* Protocol for socket. */

  7. socklen_t ai_addrlen; /* Length of socket address. */

  8. struct sockaddr *ai_addr; /* Socket address for socket. */

  9. char *ai_canonname; /* Canonical name for service location. */

  10. struct addrinfo *ai_next; /* Pointer to next in list. */

  11. };

其中ai_flags中可以设置的值为(这里之所以要列出来是因为感觉书中说的太少,而且翻译的好像跟实际的注释差别比较大,读者可以自己看注释理解,更多的信息可以通过man手册和netdb.h中看到)


 
  1. /* Possible values for `ai_flags' field in `addrinfo' structure. */

  2. # define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */

  3. # define AI_CANONNAME 0x0002 /* Request for canonical name. */

  4. # define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */

  5. # define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */

  6. # define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */

  7. # define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose

  8. returned address type.. */

  9. # ifdef __USE_GNU

  10. # define AI_IDN 0x0040 /* IDN encode input (assuming it is encoded

  11. in the current locale's character set)

  12. before looking it up. */

  13. # define AI_CANONIDN 0x0080 /* Translate canonical name from IDN format. */

  14. # define AI_IDN_ALLOW_UNASSIGNED 0x0100 /* Don't reject unassigned Unicode

  15. code points. */

  16. # define AI_IDN_USE_STD3_ASCII_RULES 0x0200 /* Validate strings according to

  17. STD3 rules. */

  18. # endif

  19. # define AI_NUMERICSERV 0x0400 /* Don't use name resolution. */

hoststname是主机名或地址串,service是服务名或十进制数的端口号字符串。调用者可以设置的hints结构的成员有ai_flags、ai_family,ai_socktype和ai_protocol。

--------------------- 本文来自 Justlinux2010 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/justlinux2010/article/details/7779715?utm_source=copy

在IPv6的应用中getaddrinfo()是很常见的,最常见的形式是:

 


 
  1. addrinfo hints;

  2. addrinfo *res = NULL;

  3.  
  4. memset(&hints,0,sizeof(hints));

  5.  
  6. hints.ai_family=AF_INET6;

  7. hints.ai_socktype=SOCK_DGRAM;

  8. hints.ai_protocol=IPPROTO_UDP;

  9. hints.ai_flags=AI_NUMERICHOST;

  10.  
  11. int rc=getaddrinfo((LPCTSTR)"2001:da8:6000:291:21f:d0ff:fed4:928c","6000",&hints,&res);


我们需要的变量是“addrinfo *res”,而hints只是一个中间过程而已。但仔细观察下,我们会发现,相比于hints变量,res也只是增加了IP地址和端口信息而已,并没有其他更多的信息加入。这时候便会有人有疑问:“为什么不像变量hints一样,直接把IP地址和端口直接指定呢?为什么非要绕个弯弯呢?”其实,我在最开始的时候也存在这样的疑问,下面让我们在看一下res在后续程序中被用到的地方。

 

SOCKET sockSrv=socket(res->ai_family, res->ai_socktype, res->ai_protocol);


但这里貌似没什么特别的(相比于hints而言)。

接着看,

 


 
  1. int ret = bind(sockSrv, res->ai_addr, res->ai_addrlen);

  2.  
  3. char bufSend[50] = "safasf";

  4. rc=sendto(sockClt, bufSend, 4, 0, res->ai_addr,res->ai_addrlen);


注意这里的res->ai_addrlen。这个变量代表地址长度。是在getaddrinfo()函数中自动获得的(当然这个我们也可以自己指定)。

看到这里,应用getaddrinfo()函数的原因已经很明显了-简化res变量的初始化。老实讲,数据类型addrinfo还是有点小复杂的(有兴趣可以研究下),如果每一个内部数据成员都要考虑初始化,还是相对麻烦的。所以,这里引入getaddrinfo()函数,使得addrinfo res的初始化变得清晰而简单。

需要补充的是,getaddrinfo()函数的用途也不只限于此的,至少它的本意是获得所有符合条件的addrinfo类型列表的。

addrinfo结构体的定义如下:

  1. struct addrinfo {
  2.      int ai_flags; /* customize behavior */
  3.      int ai_family; /* address family */
  4.      int ai_socktype; /* socket type */
  5.      int ai_protocol; /* protocol */
  6.      socklen_t ai_addrlen; /* length in bytes of address */
  7.      struct sockaddr *ai_addr; /* address */
  8.      char *ai_canonname; /* canonical name of host */
  9.      struct addrinfo *ai_next; /* next in list */
  10.      .
  11.      .
  12.      .
  13.    };

ai_family指定了地址族,可取值如下:
AF_INET          2            IPv4
AF_INET6        23            IPv6
AF_UNSPEC        0            协议无关

ai_socktype指定我套接字的类型
SOCK_STREAM        1            流
SOCK_DGRAM        2            数据报

在AF_INET通信域中套接字类型SOCK_STREAM的默认协议是TCP(传输控制协议)
在AF_INET通信域中套接字类型SOCK_DGRAM的默认协议是UDP(用户数据报协议)

ai_protocol指定协议类型。可取的值取决于ai_address和ai_socktype的值

ai_flags指定了如何来处理地址和名字,可取值如下:

getaddrinfo()-LMLPHP

getaddrinfo函数 定义及需要的头文件如下:

  1. #include <sys/socket.h>
  2. #include <netdb.h>
  3.  
  4. int getaddrinfo(const char *restrict host,
  5.                 const char *restrict service,
  6.                 const struct addrinfo *restrict hint,
  7.                 struct addrinfo **restrict res);
  8.  
  9.  
  10.  
  11.  
  12. Returns: 0 if OK, nonzero error code on error
  13.  
  14.  
  15. void freeaddrinfo(struct addrinfo *ai);

getaddrinfo函数允许将一个主机名字和服务名字映射到一个地址。

使用示例如下:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include <netdb.h>
  4. #include <arpa/inet.h>
  5.  
  6. void
  7. print_family(struct addrinfo *aip)
  8. {
  9.     printf(" family ");
  10.     switch (aip->ai_family) {
  11.     case AF_INET:
  12.         printf("inet");
  13.         break;
  14.     case AF_INET6:
  15.         printf("inet6");
  16.         break;
  17.     case AF_UNIX:
  18.         printf("unix");
  19.         break;
  20.     case AF_UNSPEC:
  21.         printf("unspecified");
  22.         break;
  23.     default:
  24.         printf("unknown");
  25.     }
  26. }
  27.  
  28. void
  29. print_type(struct addrinfo *aip)
  30. {
  31.     printf(" type ");
  32.     switch (aip->ai_socktype) {
  33.     case SOCK_STREAM:
  34.         printf("stream");
  35.         break;
  36.     case SOCK_DGRAM:
  37.         printf("datagram");
  38.         break;
  39.     case SOCK_SEQPACKET:
  40.         printf("seqpacket");
  41.         break;
  42.     case SOCK_RAW:
  43.         printf("raw");
  44.         break;
  45.     default:
  46.         printf("unknown (%d)", aip->ai_socktype);
  47.     }
  48. }
  49.  
  50. void
  51. print_protocol(struct addrinfo *aip)
  52. {
  53.     printf(" protocol ");
  54.     switch (aip->ai_protocol) {
  55.     case 0:
  56.         printf("default");
  57.         break;
  58.     case IPPROTO_TCP:
  59.         printf("TCP");
  60.         break;
  61.     case IPPROTO_UDP:
  62.         printf("UDP");
  63.         break;
  64.     case IPPROTO_RAW:
  65.         printf("raw");
  66.         break;
  67.     default:
  68.         printf("unknown (%d)", aip->ai_protocol);
  69.     }
  70. }
  71.  
  72. void
  73. print_flags(struct addrinfo *aip)
  74. {
  75.     printf("flags");
  76.     if (aip->ai_flags == 0) {
  77.         printf(" 0");
  78.     } else {
  79.         if (aip->ai_flags & AI_PASSIVE)
  80.             printf(" passive");
  81.         if (aip->ai_flags & AI_CANONNAME)
  82.             printf(" canon");
  83.         if (aip->ai_flags & AI_NUMERICHOST)
  84.             printf(" numhost");
  85. #if defined(AI_NUMERICSERV)
  86.         if (aip->ai_flags & AI_NUMERICSERV)
  87.             printf(" numserv");
  88. #endif
  89. #if defined(AI_V4MAPPED)
  90.         if (aip->ai_flags & AI_V4MAPPED)
  91.             printf(" v4mapped");
  92. #endif
  93. #if defined(AI_ALL)
  94.         if (aip->ai_flags & AI_ALL)
  95.             printf(" all");
  96. #endif
  97.     }
  98. }
  99.  
  100. int
  101. main(int argc, char *argv[])
  102. {
  103.     struct addrinfo        *ailist, *aip;
  104.     struct addrinfo        hint;
  105.     struct sockaddr_in    *sinp;
  106.     const char             *addr;
  107.     int                 err;
  108.     char                 abuf[INET_ADDRSTRLEN];
  109.  
  110.     if (argc != 3)
  111.         printf("usage: %s nodename service", argv[0]);
  112.     hint.ai_flags = AI_CANONNAME;
  113.     hint.ai_family = 0;
  114.     hint.ai_socktype = 0;
  115.     hint.ai_protocol = 0;
  116.     hint.ai_addrlen = 0;
  117.     hint.ai_canonname = NULL;
  118.     hint.ai_addr = NULL;
  119.     hint.ai_next = NULL;
  120.     if ((err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) != 0)
  121.         printf("getaddrinfo error: %s", gai_strerror(err));
  122.     for (aip = ailist; aip != NULL; aip = aip->ai_next) {
  123.         print_flags(aip);
  124.         print_family(aip);
  125.         print_type(aip);
  126.         print_protocol(aip);
  127.         printf("\n\thost %s", aip->ai_canonname?aip->ai_canonname:"-");
  128.         if (aip->ai_family == AF_INET) {
  129.             sinp = (struct sockaddr_in *)aip->ai_addr;
  130.             addr = inet_ntop(AF_INET, &sinp->sin_addr, abuf,INET_ADDRSTRLEN);
  131.             printf(" address %s", addr?addr:"unknown");
  132.             printf(" port %d", ntohs(sinp->sin_port));
  133.         }
  134.         printf("\n");
  135.     }
  136.     exit(0);
  137. }

代码说明:sinp = (struct sockaddr_in *)aip->ai_addr;会将struct sockaddr 变量强制转化为struct sockaddr_in 类型

inet_ntop函数用于在二进制格式与点分十进制格式表示(a.b.c.d)之间进行转换

执行结果:#./a X86-PC nfs

  1. root@X86-PC:/home/cheney/work-link/linux_C_Test/linux-program/fig16# ./a X86-PC nfs
  2. flags canon family inet type stream protocol TCP
  3. host X86-PC address 127.0.1.1 port 2049
  4. flags canon family inet type datagram protocol UDP
  5. host - address 127.0.1.1 port 2049
  6. root@X86-PC:/home/cheney/work-link/linux_C_Test/linux-program/fig16#
10-06 18:08