getaddrinfo

gethostbyname和gethostbyaddr這兩個函式僅僅支持IPv4,getaddrinfo函式能夠處理名字到地址以及服務到連線埠這兩種轉換,返回的是一個sockaddr結構的鍊表而不是一個地址清單。這些sockaddr結構隨後可由套接口函式直接使用。如此一來,getaddrinfo函式把協定相關性安全隱藏在這個庫函式內部。應用程式只要處理由getaddrinfo函式填寫的套接口地址結構。該函式在 POSIX規範中定義了。

函式說明

包含頭檔案

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協定 ,簡單使用示例如下所示 。

相關詞條

相關搜尋

熱門詞條

聯絡我們