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

C 語言實戰:getaddrinfo 系統呼叫完整解析

     編輯:關於C

前言

承接前文 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) 釋放記憶體。

傳回值與錯誤處理

  • 成功:回傳 0。
  • 失敗:回傳非零錯誤碼(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;
}

關鍵重點總結

  1. getaddrinfo 取代舊有 gethostbyname,支援 IPv6、線程安全、自動處理位元組序。
  2. hints 靈活篩選回傳結果,減少應用層邏輯。
  3. 回傳的鏈結串列為動態記憶體,務必配對 freeaddrinfo 釋放,否則洩漏。
  4. 遍歷串列嘗試連線,可實現 Happy Eyeballs 機制(IPv6 優先並快速回退 IPv4)。

掌握 getaddrinfo,是編寫可攜、健壯網路程式的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved