函式說明
包含頭檔案
Linux下為#include<netdb.h>
windows下為#include <ws2tcpip.h>
函式原型
int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );
參數說明
hostname:一個主機名或者地址串(IPv4的點分十進制串或者IPv6的16進制串)
service:服務名可以是十進制的連線埠號,也可以是已定義的服務名稱,如ftp、http等
hints:可以是一個空指針,也可以是一個指向某個addrinfo結構體的指針,調用者在這個結構中填入關於期望返回的信息類型的暗示。舉例來說:指定的服務既可支持TCP也可支持UDP,所以調用者可以把hints結構中的ai_socktype成員設定成SOCK_DGRAM使得返回的僅僅是適用於數據報套接口的信息。
result:本函式通過result指針參數返回一個指向addrinfo結構體鍊表的指針。
返回值:0——成功,非0——出錯
參數設定
在getaddrinfo函式之前通常需要對以下6個參數進行以下設定:nodename、servname、hints的ai_flags、ai_family、ai_socktype、ai_protocol。
在6項參數中,對函式影響最大的是nodename,sername和 h i n t s . ai_flag,而ai_family只是有地址為v4地址或v6地址的區別。ai_protocol一般是為0不作改動。
getaddrinfo在實際使用中的幾種常用參數設定
參數說明
在getaddrinfo函式之前通常需要對以下6個參數進行以下設定:nodename、servname、hints的ai_flags、ai_family、ai_socktype、ai_protocol
在6項參數中,對函式影響最大的是nodename,sername和hints
而ai_family只是有地址為v4地址或v6地址的區別。而ai_protocol一般是為0不作改動。
其中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_flags的值的範圍為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。
函式使用示例
getaddrinfo函式是gethostbyname的替代函式,其支持IPV4和IPV6協定 ,簡單使用示例如下所示 。