您的位置:首页 > 运维架构

getaddrinfo()

2014-12-04 00:00 375 查看

getaddrinfo()

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地址与端口号.

domain;可以是域名,也可以是IP地址的点分十进制表示,或者是0;

service;可以是服务名,如"http","ftp";也可以是端口号的十进制字符串,如"80","23";或者是0

若取0,则查询结果中的端口号是未设置的,此时还需手动赋值!

hints,指向着一个 addrinfo 结构体,该结构体除了以下指定的域外,其他域应该取值为0,或者NULL;

ai_family;用来限定 getaddrinfo() 的查询结果中 ai_family 的取值;可以是 AF_INET(此时 getaddrinfo() 查询结果中 ai_family 的取值只能是 AF_INET),或者 AF_INET6,或者 AF_UNSPEC(不限定查询结果中ai_family的取值);

ai_socktype;用来限定查询结果中 ai_socktype 的取值;可以是 SOCK_STREAM,SOCK_DGRAM;或者为0,表示不限定;

ai_protocol;用来限定查询结果中 ai_protocol 的取值;若为0,则表示不限定

ai_flags;位掩码,可以是以下值,或者它们或运算的结果:

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


freeaddrinfo()

void freeaddrinfo(struct addrinfo *res);


释放 getaddrinfo() 返回的单链表.

gai_strerror()

const char *gai_strerror(int errcode);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息