Linux 下用getaddrinfo、getnameinfo实现IP和域名的转换

gethostbyname, gethostbyaddr是不可重入函数;已经被getaddrinfo, getnameinfo替代

getaddrinfo 将主机和服务转换到socket地址,融合了函数getipnodebyname, getipnodebyaddr, getservbyname, getservbyport的功能,是可重入的
getnameinfo 功能与getaddrinfo相反,它将socket地址转换到主机和服务,融合了函数gethostbyaddr、getservbyport的功能,是可重入的

函数原型:
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);

addrinfo 结构体定义如下:
    
    struct addrinfo {
           int     ai_flags;
           int     ai_family;
           int     ai_socktype;
           int     ai_protocol;
           size_t  ai_addrlen;
           struct sockaddr *ai_addr;
           char   *ai_canonname;
           struct addrinfo *ai_next;
    };

函数参数说明:
    node或service参数最多可能有一个为NULL。
    node 要么为点分式地址(IPv4-点分十进制, IPv6-十六进制) 要么为主机名。如果hints.ai_flags包含了AI_NUMERICHOST标志,则node必须为数字地址。
    service为端口号或者端口名。如果不为空,为端口名,则必须可以解析,通过/etc/services。
    如果hints.ai_flags指定了AI_CANONNAME标志,则返回的结构体列表中第一个addrinfo结构体的ai_canonname域指向了主机的正式名字    
     如果hints.ai_flags指定了AI_PASSIVE标志,而且node为NULL,则返回的地址包含INADDR_ANY或IN6ADDR_ANY_INIT适合用来bind将要accept连接的socket。
    如果hints.ai_flags指定了AI_PASSIVE标志,而且node不为NULL,则忽略AI_PASSIVE。
    如果hints.ai_flags未指定AI_PASSIVE标志,则返回的地址适合用来connect,sendto,sendmsg。
    如果hints.ai_flags未指定AI_PASSIVE标志,而且node为NULL, 则返回回环地址,用于本地服务。
    根据node和service查找到对应的addr info。如果此信息被connect调用,则表示这是被监听对象;而监听者可以通过node里面设置。node如果是fe80这种IP V6地址,必须接%eth来指定接口,则监听者就是这个local IP;如果是raw socket,则监听端口就是hints里面的 ai_protocol。  getaddrinfo() supports the address%scope-id notation for specifying the IPv6 scope-ID.

int ip_to_hostname(const char* ip)
{
        int ret = 0;

        if(!ip)
        {
                printf("invalid params\n");
                return -1;
        }

        struct addrinfo hints;
        struct addrinfo *res, *res_p;
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_CANONNAME | AI_NUMERICHOST;
        hints.ai_protocol = 0;

        ret = getaddrinfo(ip, NULL, &hints, &res);
        if(ret != 0)
        {
                printf("getaddrinfo: %s\n", gai_strerror(ret));
                return -1;
        }

        for(res_p = res; res_p != NULL; res_p = res_p->ai_next)
        {
                char host[1024] = {0};
                ret = getnameinfo(res_p->ai_addr, res_p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NAMEREQD);
                if(ret != 0)
                {
                        printf("getnameinfo: %s\n", gai_strerror(ret));
                }
                else
                {
                        printf("hostname: %s\n", host);
                }
        }

        freeaddrinfo(res);
        return ret;
}
int hostname_to_ip(const char* hostname)
{
        int ret = 0;

        if(!hostname)
        {
                printf("invalid params\n");
                return -1;
        }

        struct addrinfo hints;
        struct addrinfo *res, *res_p;
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_CANONNAME;
        hints.ai_protocol = 0;

        ret = getaddrinfo(hostname, NULL, &hints, &res);
        if(ret != 0)
        {
                printf("getaddrinfo: %s\n", gai_strerror(ret));
                return -1;
        }

        for(res_p = res; res_p != NULL; res_p = res_p->ai_next)
        {
                char host[1024] = {0};
                ret = getnameinfo(res_p->ai_addr, res_p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
                if(ret != 0)
                {
                        printf("getnameinfo: %s\n", gai_strerror(ret));
                }
                else
                {
                        printf("ip: %s\n", host);
                }
        }

        freeaddrinfo(res);
        return ret;
}

 

你可能感兴趣的:(linux,开发,计算机网络,网络通信)