其中ai_flags、ai_family、ai_socktype說明如下:
參數 取值 值 說明
ai_family AF_INET 2 IPv4
AF_INET6 23 IPv6
AF_UNSPEC 0 協議無關
ai_protocol IPPROTO_IP 0 IP協議
IPPROTO_IPV4 4 IPv4
IPPROTO_IPV6 41 IPv6
IPPROTO_UDP 17 UDP
IPPROTO_TCP 6 TCP
ai_socktype SOCK_STREAM 1 流
SOCK_DGRAM 2 數據報
ai_flags AI_PASSIVE 1 被動的,用於bind,通常用於server socket
AI_CANONNAME 2
AI_NUMERICHOST 4 地址爲數字串
對於ai_flags值的說明:
AI_NUMERICHOST AI_CANONNAME AI_PASSIVE
0/1 0/1 0/1
如上表所示,ai_flagsde值範圍爲0~7,取決於程序如何設置3個標誌位,比如設置ai_flags爲 “AI_PASSIVE|AI_CANONNAME”,ai_flags值就爲3。三個參數的含義分別爲:
(1)AI_PASSIVE當此標誌置位時,表示調用者將在bind()函數調用中使用返回的地址結構。當此標誌不置位時,表示將在connect()函數調用中使用。
當節點名位NULL,且此標誌置位,則返回的地址將是通配地址。
如果節點名NULL,且此標誌不置位,則返回的地址將是迴環地址。
(2)AI_CANNONAME當此標誌置位時,在函數所返回的第一個addrinfo結構中的ai_cannoname成員中,應該包含一個以空字符結尾的字符串,字符串的內容是節點名的正規名。
(3)AI_NUMERICHOST當此標誌置位時,此標誌表示調用中的節點名必須是一個數字地址字符串。
實際使用的幾種常用設置
一般情況下,client/server編程中,server端調用bind(如果面向連接的還需要listen),client則不用掉bind函數,解析地址後直接connect(面向連接)或直接發送數據(無連接)。因此,比較常見的情況有
(1) 通常服務器端在調用getaddrinfo之前,ai_flags設置AI_PASSIVE,用於bind;主機名nodename通常會設置爲NULL,返回通配地址[::]。
(2) 客戶端調用getaddrinfo時,ai_flags一般不設置AI_PASSIVE,但是主機名nodename和服務名servname(更願意稱之爲端口)則應該不爲空。
(3) 當然,即使不設置AI_PASSIVE,取出的地址也並非不可以被bind,很多程序中ai_flags直接設置爲0,即3個標誌位都不設置,這種情況下只要hostname和servname設置的沒有問題就可以正確bind。
上述情況只是簡單的client/server中的使用,但實際在使用getaddrinfo和參考國外開源代碼的時候,曾遇到一些將servname(即端口)設爲NULL的情況
(當然,此時nodename必不爲NULL,否則調用getaddrinfo會報錯)。以下分情況進行了測試:
(1) 如果nodename是字符串型的IPv6地址,bind的時候會分配臨時端口;
(2) 如果nodename是本機名,servname爲NULL,則根據操作系統的不同略有不同,本文僅在WinXP和Win2003上作了測試。
a) WinXP系統(SP2)返回loopback地址[::1]
b)Win2003則將本機的所有IPv6地址列表加以返回。因爲通常一臺IPv6主機都有可能不止一個IPv6地址,比如fe80::1(本機loopback地址)、fe80::***的Link-Local地址、3ffe:***的全局地址等等。這種情況下調用getaddrinfo會將這些地址全部返回,調用者應該注意如何使用這些地址。另外要注意的是,對於fe80::的地址在綁定的時候必須標明接口地址,即使用fe80::20d:60ff:fe78:51c2%4或fe80::1%1這樣的地址格式,通過getaddrinfo直接取出fe80地址好像無法直接bind。
在Windows環境調試IPv6的程序個人感覺還是使用WinXP(SP2)和Win2003基本上沒有太大的區別,使用Win2003更規範一些。
用VC編寫和調試IPv6的程序一定要安裝Windows較新的SDK,我安裝的是MS_Platform_SDK_Feb_2003,否則庫函數和頭文件可能都會有問題。