getaddrinfo()

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

你可能感兴趣的:(getopt,getopt_long,getaddrinfo)