承接前文 Socket 通訊位址系統呼叫,本文深入解析 getaddrinfo——現代網路程式解析主機名、服務名、取得 Socket 位址資訊的核心 API。它不僅自動處理位元組序轉換,更能依條件篩選協定族、Socket 類型與協定,回傳鏈結串列供多地址選擇。
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
struct addrinfo {
int ai_flags; // 輸入:控制行為標誌
int ai_family; // 輸入/輸出:協定族 (AF_INET, AF_INET6, AF_UNSPEC)
int ai_socktype; // 輸入/輸出:Socket 類型 (SOCK_STREAM, SOCK_DGRAM)
int ai_protocol; // 輸入/輸出:協定 (0 表預設)
socklen_t ai_addrlen; // 輸出:位址長度
struct sockaddr *ai_addr; // 輸出:Socket 位址指標
char *ai_canonname; // 輸出:規範主機名
struct addrinfo *ai_next; // 輸出:下一個結果節點
};
node:主機名或 IP 位址字串(如 "www.example.com"、"192.168.1.1")。service:服務名("http")或連接埠號字串("80")。hints:篩選條件模板,僅使用前四個欄位,其餘設 0/NULL。
ai_flags:常用 AI_ADDRCONFIG(僅回傳本機配置的位址族)、AI_PASSIVE(用於 bind 的野卡位址)等。ai_family:AF_INET (IPv4)、AF_INET6 (IPv6)、AF_UNSPEC (全部)。ai_socktype:SOCK_STREAM (TCP)、SOCK_DGRAM (UDP)、0 (全部)。ai_protocol:通常設 0 使用預設協定。res 指向動態分配的 addrinfo 鏈結串列。每個節點包含一組完整的 Socket 位址資訊,可直接用於 socket()、connect()、bind()。使用完畢必須呼叫 freeaddrinfo(res) 釋放記憶體。
EAI_* 系列),可用 gai_strerror(err) 取得錯誤訊息。#include
#include
#include
#include
#include
#include
#include
int main() {
struct addrinfo hints = {0}, *res, *p;
hints.ai_family = AF_UNSPEC; // IPv4/IPv6 皆可
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_ADDRCONFIG; // 僅本機支援的族
int err = getaddrinfo("example.com", "80", &hints, &res);
if (err != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return 1;
}
int sockfd = -1;
for (p = res; p != NULL; p = p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == -1) continue;
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == 0) break; // 成功
close(sockfd);
sockfd = -1;
}
freeaddrinfo(res); // 釋放鏈結串列
if (sockfd == -1) {
perror("connect");
return 1;
}
printf("Connected successfully!\n");
close(sockfd);
return 0;
}
getaddrinfo 取代舊有 gethostbyname,支援 IPv6、線程安全、自動處理位元組序。hints 靈活篩選回傳結果,減少應用層邏輯。freeaddrinfo 釋放,否則洩漏。掌握 getaddrinfo,是編寫可攜、健壯網路程式的基石。