網路與通訊端

通訊端位址與 getaddrinfo/DNS(socket address and name resolution)

/ DNS -> DEE-EN-ESS, getaddrinfo -> get-ADDR-info /

當你告訴通訊端 API 要連到哪裡或綁定到哪裡時,你不能只是把「example.com,連接埠 80」這幾個字交給它。核心處理的是數字——一個數值 IP 位址與一個數值連接埠,打包進一個固定結構。通訊端位址就是那個打包好的結構(sockaddr);而把像 example.com 這樣的人類名稱變成它的工作,叫做名稱解析,由 DNS 完成、並由 getaddrinfo() 替你包裝起來。

這個結構:bind() 與 connect() 取一個指向 struct sockaddr 的指標,裡頭存著位址族(IPv4 或 IPv6)、一個連接埠,以及一個 IP 位址,全都以固定的位元組排佈、數字採用網路位元組序。實務上你很少手動填它。你會改呼叫 getaddrinfo("example.com", "80", &hints, &result),它做兩件事:查詢 DNS(網域名稱系統,網際網路那本把名稱對應到 IP 位址的分散式電話簿)找出 IP,並回傳一份現成的 sockaddr 結構清單,讓你能直接傳給 connect()。它替你處理 IPv4 與 IPv6、以及多個位址,這正是為什麼現代程式碼用它,而不手動建構位址。

為何重要:這是人類使用的友善名稱與網路所需數字之間的橋樑。每次你打一個網域名稱,某個東西都會先執行這次查詢。現代的建議很堅定:用 getaddrinfo() 而非較舊、只支援 IPv4 的輔助函式,因為它是那唯一一個能同時處理兩種 IP 版本、正確填好 sockaddr、並讓你不必手動操心位元組序的呼叫。記得查詢可能失敗(名稱不存在、沒有網路),也可能花時間,所以要像對待任何其他呼叫一樣檢查它的結果。

struct addrinfo hints = {0}, *res; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; getaddrinfo("example.com", "80", &hints, &res); /* res 現在列出可供 connect() 使用的 sockaddr;用 freeaddrinfo(res) 釋放 */ AF_UNSPEC 代表「IPv4 或 IPv6,哪個能用就用哪個」。

getaddrinfo() 把名稱與連接埠變成可直接使用的 sockaddr,替你處理 DNS 與 IP 版本。

DNS 解析是在你連線之前發生的、獨立的網路步驟,它本身也可能失敗(名稱錯誤、沒有 DNS 伺服器)。記得用 freeaddrinfo() 釋放那份清單,以免洩漏。

又稱
sockaddrname resolutionDomain Name System通訊端位址結構網域名稱系統