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);