int getaddrinfo(const char *domain, const char *service, const struct addrinfo *hints, struct addrinfo **res); struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; };
查询给定的域名 domain,与服务名 service,并返回对应的IP地址与端口号.shell
domain;能够是域名,也能够是IP地址的点分十进制表示,或者是0;app
service;能够是服务名,如"http","ftp";也能够是端口号的十进制字符串,如"80","23";或者是0dom
若取0,则查询结果中的端口号是未设置的,此时还需手动赋值!
spa
hints,指向着一个 addrinfo 结构体,该结构体除了如下指定的域外,其余域应该取值为0,或者NULL;指针
ai_family;用来限定 getaddrinfo() 的查询结果中 ai_family 的取值;能够是 AF_INET(此时 getaddrinfo() 查询结果中 ai_family 的取值只能是 AF_INET),或者 AF_INET6,或者 AF_UNSPEC(不限定查询结果中ai_family的取值);
code
ai_socktype;用来限定查询结果中 ai_socktype 的取值;能够是 SOCK_STREAM,SOCK_DGRAM;或者为0,表示不限定;
orm
ai_protocol;用来限定查询结果中 ai_protocol 的取值;若为0,则表示不限定
ip
ai_flags;位掩码,能够是如下值,或者它们或运算的结果:ci
AI_NUMERICHOST;此时代表 domain 是IP地址的点分十进制;不是域名,此时不会执行DNS查询.
字符串
AI_NUMERICSERV;此时代表 service 只是端口号的字符串表示;不是服务名,
AI_PASSIVE;仅当 domain == 0 时起做用;当 domain==0 时,若设置了该标志,则查询结果中的IP地址是通配地址;若未设置该标志,则IP地址是环回地址.
AI_CANONNAME;若设置了该标志,则 *res->ai_canonname 域中存放着目的主机(即 domain 指定的主机)的 official name(我理解为彻底限定域名).
AI_ADDRCONFIG;若设置了该标志,则仅当本地主机至少配置了一个IPV4(或IPV6)地址时,才会在返回的查询结果中包含IPV4(或IPV6)地址;以下:
域名 对应着以下 IP 地址: 173.194.127.180 173.194.127.176 2404:6800:4005:802::1010 若本地主机仅配置了 IPV4 地址,则返回的查询结果中不包含 IPV6 地址,即此时只有: 173.194.127.180 173.194.127.176 一样若本地主机仅配置了 IPV6 地址,则返回的查询结果中仅包含IPV6地址.
若 hints==0,则至关于 ai_family==AF_UNSPEC,ai_socktype==0,ai_protocol==0,ai_flags==AI_ADDRCONFIG|AI_V4MAPPED.
res;getaddrinfo() 返回的查询结果是一个单链表,链表中每个元素类型为 struct addrinfo;链表的第一个元素的指针存放在 *res 中.
返回值;若不为0,则代表查询出错,此时返回值表示出错码;返回0,表示查询成功.
ByteArray family_to_str(int family){ if(family == AF_INET) return "AF_INET"; if(family == AF_INET6) return "AF_INET6"; ByteArray result("Unknow"); result.appendFormat("(%d)",family); return result; } ByteArray socktype_to_str(int socktype){ if(socktype == SOCK_STREAM) return "SOCK_STREAM"; if(socktype == SOCK_DGRAM) return "SOCK_DGRAM"; ByteArray result("Unknow"); result.appendFormat("(%d)",socktype); return result; } ByteArray procotol_to_str(int proto){ if(proto == IPPROTO_TCP) return "TCP"; if(proto == IPPROTO_UDP) return "UDP"; ByteArray result("Unknow"); result.appendFormat("(%d)",proto); return result; } void print_addrinfo(const struct addrinfo *addr_info){ printf("faimly: %s\nsocktype: %s\nprotocol: %s\ncannoname: %s\n" ,family_to_str(addr_info->ai_family).constData() ,socktype_to_str(addr_info->ai_socktype).constData() ,procotol_to_str(addr_info->ai_protocol).constData() ,addr_info->ai_canonname); if(addr_info->ai_addr->sa_family == AF_INET){ struct sockaddr_in *addr_ptr = (struct sockaddr_in*)addr_info->ai_addr; char buf[INET_ADDRSTRLEN]; if(inet_ntop(AF_INET,&addr_ptr->sin_addr,buf,INET_ADDRSTRLEN) == 0) SystemCallFailed(inet_ntop); printf("ipv4: %s\nport: %d\n",buf,ntohs(addr_ptr->sin_port)); }else if(addr_info->ai_addr->sa_family == AF_INET6){ struct sockaddr_in6 *addr_ptr = (struct sockaddr_in6*)addr_info->ai_addr; char buf[INET6_ADDRSTRLEN]; if(inet_ntop(AF_INET6,&addr_ptr->sin6_addr,buf,INET6_ADDRSTRLEN) == 0) SystemCallFailed(inet_ntop); printf("ipv6: %s\nport: %d\n",buf,ntohs(addr_ptr->sin6_port)); }else printf("ip: Unknow\nport: Unknow\n"); } int main(int argc,char *argv[]){ if(argc < 3){ printf("%s 域名/IP地址 服务名/端口号\n",argv[0]); return 1; } int core_ret; struct addrinfo *result; struct addrinfo hints; memset(&hints,0,sizeof(hints)); hints.ai_flags = AI_CANONNAME; core_ret = getaddrinfo(argv[1],argv[2],&hints,&result); if(core_ret != 0) ThrowException(0,"func=getaddrinfo;ret_code=%d;err_str=%s",core_ret,gai_strerror(core_ret)); while(result){ print_addrinfo(result); putchar('\n'); result = result->ai_next; } return 0; }
# 程序运行结果 # 此时域名 m 解析后获得一个 IPV4 地址.服务名 http 解析后获得一个端口号,但支持 TCP,UDP 2种协议.因此总可能数:1(1种IP地址)*2(2种协议)=2 # 将根据解析出的IP地址的类型设置 ai_family 域(即若IP地址是IPV4地址,则为 AF_INET,若为IPV6地址,则设置为 AF_INET6). # 根据服务名支持的协议设置 ai_socktype,ai_protocol; $ ./Test www.so.com http faimly: AF_INET socktype: SOCK_STREAM protocol: TCP cannoname: so.qh-lb.com ipv4: 101.4.60.8 port: 80 faimly: AF_INET socktype: SOCK_DGRAM protocol: UDP cannoname: (null) ipv4: 101.4.60.8 port: 80 #此时域名 解析后获得一个 IPV4 地址;服务名 ftp 解析后获得一个端口号,而且只支持 TCP 协议,因此总可能数: 1*1=1; $ ./Test www.360.cn ftp faimly: AF_INET socktype: SOCK_STREAM protocol: TCP cannoname: www.360.cn ipv4: 101.4.60.193 port: 21
void freeaddrinfo(struct addrinfo *res);
释放 getaddrinfo() 返回的单链表.
const char *gai_strerror(int errcode);