getaddrinfo接口
getaddrinfo通过res来返回一个指向struct addrinfo结构链表的指针(注意这里返回的是一个链表),struct addrinfo结构的定义如下所示:
-
struct addrinfo
-
{
-
int ai_flags; /* Input flags. */
-
int ai_family; /* Protocol family for socket. */
-
int ai_socktype; /* Socket type. */
-
int ai_protocol; /* Protocol for socket. */
-
socklen_t ai_addrlen; /* Length of socket address. */
-
struct sockaddr *ai_addr; /* Socket address for socket. */
-
char *ai_canonname; /* Canonical name for service location. */
-
struct addrinfo *ai_next; /* Pointer to next in list. */
-
};
其中ai_flags中可以设置的值为(这里之所以要列出来是因为感觉书中说的太少,而且翻译的好像跟实际的注释差别比较大,读者可以自己看注释理解,更多的信息可以通过man手册和netdb.h中看到)
-
/* Possible values for `ai_flags' field in `addrinfo' structure. */
-
# define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */
-
# define AI_CANONNAME 0x0002 /* Request for canonical name. */
-
# define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */
-
# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */
-
# define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */
-
# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
-
returned address type.. */
-
# ifdef __USE_GNU
-
# define AI_IDN 0x0040 /* IDN encode input (assuming it is encoded
-
in the current locale's character set)
-
before looking it up. */
-
# define AI_CANONIDN 0x0080 /* Translate canonical name from IDN format. */
-
# define AI_IDN_ALLOW_UNASSIGNED 0x0100 /* Don't reject unassigned Unicode
-
code points. */
-
# define AI_IDN_USE_STD3_ASCII_RULES 0x0200 /* Validate strings according to
-
STD3 rules. */
-
# endif
-
# 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()是很常见的,最常见的形式是:
-
addrinfo hints;
-
addrinfo *res = NULL;
-
memset(&hints,0,sizeof(hints));
-
hints.ai_family=AF_INET6;
-
hints.ai_socktype=SOCK_DGRAM;
-
hints.ai_protocol=IPPROTO_UDP;
-
hints.ai_flags=AI_NUMERICHOST;
-
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而言)。
接着看,
-
int ret = bind(sockSrv, res->ai_addr, res->ai_addrlen);
-
char bufSend[50] = "safasf";
-
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结构体的定义如下:
- struct addrinfo {
- int ai_flags; /* customize behavior */
- int ai_family; /* address family */
- int ai_socktype; /* socket type */
- int ai_protocol; /* protocol */
- socklen_t ai_addrlen; /* length in bytes of address */
- struct sockaddr *ai_addr; /* address */
- char *ai_canonname; /* canonical name of host */
- struct addrinfo *ai_next; /* next in list */
- .
- .
- .
- };
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函数 定义及需要的头文件如下:
- #include <sys/socket.h>
- #include <netdb.h>
- int getaddrinfo(const char *restrict host,
- const char *restrict service,
- const struct addrinfo *restrict hint,
- struct addrinfo **restrict res);
- Returns: 0 if OK, nonzero error code on error
- void freeaddrinfo(struct addrinfo *ai);
getaddrinfo函数允许将一个主机名字和服务名字映射到一个地址。
使用示例如下:
- #include<stdio.h>
- #include<stdlib.h>
- #include <netdb.h>
- #include <arpa/inet.h>
- void
- print_family(struct addrinfo *aip)
- {
- printf(" family ");
- switch (aip->ai_family) {
- case AF_INET:
- printf("inet");
- break;
- case AF_INET6:
- printf("inet6");
- break;
- case AF_UNIX:
- printf("unix");
- break;
- case AF_UNSPEC:
- printf("unspecified");
- break;
- default:
- printf("unknown");
- }
- }
- void
- print_type(struct addrinfo *aip)
- {
- printf(" type ");
- switch (aip->ai_socktype) {
- case SOCK_STREAM:
- printf("stream");
- break;
- case SOCK_DGRAM:
- printf("datagram");
- break;
- case SOCK_SEQPACKET:
- printf("seqpacket");
- break;
- case SOCK_RAW:
- printf("raw");
- break;
- default:
- printf("unknown (%d)", aip->ai_socktype);
- }
- }
- void
- print_protocol(struct addrinfo *aip)
- {
- printf(" protocol ");
- switch (aip->ai_protocol) {
- case 0:
- printf("default");
- break;
- case IPPROTO_TCP:
- printf("TCP");
- break;
- case IPPROTO_UDP:
- printf("UDP");
- break;
- case IPPROTO_RAW:
- printf("raw");
- break;
- default:
- printf("unknown (%d)", aip->ai_protocol);
- }
- }
- void
- print_flags(struct addrinfo *aip)
- {
- printf("flags");
- if (aip->ai_flags == 0) {
- printf(" 0");
- } else {
- if (aip->ai_flags & AI_PASSIVE)
- printf(" passive");
- if (aip->ai_flags & AI_CANONNAME)
- printf(" canon");
- if (aip->ai_flags & AI_NUMERICHOST)
- printf(" numhost");
- #if defined(AI_NUMERICSERV)
- if (aip->ai_flags & AI_NUMERICSERV)
- printf(" numserv");
- #endif
- #if defined(AI_V4MAPPED)
- if (aip->ai_flags & AI_V4MAPPED)
- printf(" v4mapped");
- #endif
- #if defined(AI_ALL)
- if (aip->ai_flags & AI_ALL)
- printf(" all");
- #endif
- }
- }
- int
- main(int argc, char *argv[])
- {
- struct addrinfo *ailist, *aip;
- struct addrinfo hint;
- struct sockaddr_in *sinp;
- const char *addr;
- int err;
- char abuf[INET_ADDRSTRLEN];
- if (argc != 3)
- printf("usage: %s nodename service", argv[0]);
- hint.ai_flags = AI_CANONNAME;
- hint.ai_family = 0;
- hint.ai_socktype = 0;
- hint.ai_protocol = 0;
- hint.ai_addrlen = 0;
- hint.ai_canonname = NULL;
- hint.ai_addr = NULL;
- hint.ai_next = NULL;
- if ((err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) != 0)
- printf("getaddrinfo error: %s", gai_strerror(err));
- for (aip = ailist; aip != NULL; aip = aip->ai_next) {
- print_flags(aip);
- print_family(aip);
- print_type(aip);
- print_protocol(aip);
- printf("\n\thost %s", aip->ai_canonname?aip->ai_canonname:"-");
- if (aip->ai_family == AF_INET) {
- sinp = (struct sockaddr_in *)aip->ai_addr;
- addr = inet_ntop(AF_INET, &sinp->sin_addr, abuf,INET_ADDRSTRLEN);
- printf(" address %s", addr?addr:"unknown");
- printf(" port %d", ntohs(sinp->sin_port));
- }
- printf("\n");
- }
- exit(0);
- }
代码说明:sinp = (struct sockaddr_in *)aip->ai_addr;会将struct sockaddr 变量强制转化为struct sockaddr_in 类型
inet_ntop函数用于在二进制格式与点分十进制格式表示(a.b.c.d)之间进行转换
执行结果:#./a X86-PC nfs
- root@X86-PC:/home/cheney/work-link/linux_C_Test/linux-program/fig16# ./a X86-PC nfs
- flags canon family inet type stream protocol TCP
- host X86-PC address 127.0.1.1 port 2049
- flags canon family inet type datagram protocol UDP
- host - address 127.0.1.1 port 2049
- root@X86-PC:/home/cheney/work-link/linux_C_Test/linux-program/fig16#