首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Beej 網絡編程指南第 8 篇:getaddrinfo() 統一位址解析介面

     編輯:關於C

歷史背景

早期使用 gethostbyname() 做 DNS 查詢,再手工填充 sockaddr_in,僅支援 IPv4,程式碼繁瑣且不可移植。

getaddrinfo() 原型

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

int getaddrinfo(const char *node,      // 主機名或 IP
                const char *service,   // 埠號或服務名("http", "80")
                const struct addrinfo *hints,
                struct addrinfo **res); // 返回鏈表頭

關鍵結構體 addrinfo

struct addrinfo {
    int              ai_flags;
    int              ai_family;      // AF_INET, AF_INET6, AF_UNSPEC
    int              ai_socktype;    // SOCK_STREAM, SOCK_DGRAM
    int              ai_protocol;    // 0, IPPROTO_TCP, IPPROTO_UDP
    size_t           ai_addrlen;     // ai_addr 大小
    struct sockaddr *ai_addr;        // 位址結構
    char            *ai_canonname;   // 規範主機名
    struct addrinfo *ai_next;        // 下一個節點
};

伺服器端範例(被動開啟)

struct addrinfo hints, *servinfo;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;  // 自動填入本機 IP

getaddrinfo(NULL, "3490", &hints, &servinfo);
// servinfo 指向鏈表,遍歷嘗試 socket/bind/listen
freeaddrinfo(servinfo); // 釋放鏈表

客戶端範例(主動連線)

struct addrinfo hints, *servinfo;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
// 無 AI_PASSIVE
getaddrinfo("www.example.net", "3490", &hints, &servinfo);
// 遍歷鏈表嘗試 socket/connect

showip.c 示範:列印主機所有 IP

流程圖

// 遍歷 servinfo 鏈表
for (struct addrinfo *p = servinfo; p != NULL; p = p->ai_next) {
    void *addr;
    char ipstr[INET6_ADDRSTRLEN];
    if (p->ai_family == AF_INET) {
        addr = &((struct sockaddr_in*)p->ai_addr)->sin_addr;
    } else {
        addr = &((struct sockaddr_in6*)p->ai_addr)->sin6_addr;
    }
    inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
    printf("%s\n", ipstr);
}

重要提醒

  • 必須檢查返回值,非 0 表示錯誤,用 gai_strerror() 取得錯誤字串。
  • 返回的鏈表可能包含多個位址(IPv4/IPv6、多介面),應遍歷嘗試 而非只用第一個。
  • 用完後必須呼叫 freeaddrinfo() 釋放記憶體。
  • AI_PASSIVE 僅用於伺服器端綁定通配位址。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved