跳转到内容

C 编程/POSIX 参考/netdb.h/getaddrinfo

来自维基教科书,开放的书籍,面向开放的世界

getaddrinfo()getnameinfo() 函数是 POSIX 标准应用程序编程接口 (API) 的一部分,用于在域名系统 (DNS) 主机名和 IP 地址之间转换其人类可读的文本表示形式和操作系统网络 API 的结构化二进制格式。

getaddrinfo()getnameinfo()是彼此的逆函数。

这套函数完全独立于网络协议,支持 IPv4 和 IPv6。它是构建独立于协议的应用程序和将旧版 IPv4 代码迁移到 IPv6 互联网中进行名称解析的推荐接口。

struct addrinfo

[编辑 | 编辑源代码]

用于在网络 API 中表示地址和主机名的 C 数据结构如下

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;     /* canonical name */
    struct  addrinfo *ai_next; /* this struct can form a linked list */
};

在最近的操作系统中,ai_addrlen 的类型已从 size_t 更改为 socklen_t。大多数套接字函数(如 accept 和 getpeername)需要 socklen_t* 参数,程序员经常将地址传递给 addrinfo 结构的 ai_addrlen 元素。如果类型不兼容,例如在 size_t 为 8 字节而 socklen_t 为 4 字节的大端 64 位 Solaris 9 系统上,则可能会导致运行时错误。

getaddrinfo()

[编辑 | 编辑源代码]

getaddrinfo()将表示主机名或 IP 地址的人类可读文本字符串转换为动态分配的struct addrinfo结构的链表。应用程序可以使用freeaddrinfo()函数释放这些链表。这些函数的函数原型指定如下

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char *node,
                const char *service,
                const struct addrinfo *hints,
                struct addrinfo **res);

void freeaddrinfo(struct addrinfo *res);

getnameinfo()

[编辑 | 编辑源代码]

getnameinfo()struct sockaddr指针形式的 IP 地址的内部二进制表示形式转换为文本字符串,该字符串包含主机名或(如果地址无法解析为名称)文本 IP 地址表示形式,以及服务端口名称或编号。函数原型指定如下

#include <sys/socket.h>
#include <netdb.h>

int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                char *host, size_t hostlen,
                char *serv, size_t servlen,
                int flags);

以下示例使用getaddrinfo()将域名 www.example.com 解析为其地址列表,然后调用getnameinfo()在每个结果上返回该地址的规范名称。通常,这将生成原始主机名,除非特定地址具有多个名称,在这种情况下,将返回规范名称。在此示例中,域名将打印三次,每次都对应于获得的三个结果之一。

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>

#ifndef   NI_MAXHOST
#define   NI_MAXHOST 1025
#endif

int main(void)
{
    struct addrinfo *result;
    struct addrinfo *res;
    int error;

    /* resolve the domain name into a list of addresses */
    error = getaddrinfo("www.example.com", NULL, NULL, &result);
    if (error != 0)
    {   
        fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
        return EXIT_FAILURE;
    }   

    /* loop over all returned results and do inverse lookup */
    for (res = result; res != NULL; res = res->ai_next)
    {   
        char hostname[NI_MAXHOST] = "";

        error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); 
        if (error != 0)
        {
            fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
            continue;
        }
        if (*hostname != '\0')
            printf("hostname: %s\n", hostname);
    }   

    freeaddrinfo(result);
    return EXIT_SUCCESS;
}
[编辑 | 编辑源代码]
  • RFC 3493,IPv6 的基本套接字接口扩展
华夏公益教科书