跳轉到內容

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 的基本套接字介面擴充套件
華夏公益教科書