生活随笔
收集整理的這篇文章主要介紹了
IPv6名称到地址的转换函数getaddrinfo()详解
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
? IPv4 中使用 gethostbyname() 函數(shù)完成主機(jī)名到地址解析,但是該 API 不允許調(diào)用者指定所需地址類(lèi)型的任何信息,返回的結(jié)構(gòu)只包含了用于存儲(chǔ) IPv4 地址的空間。為了解決該問(wèn)題, IPv6 中引入了 getaddrinfo() 的新 API ,它是協(xié)議無(wú)關(guān)的,既可用于 IPv4 也可用于 IPv6 。調(diào)用該函數(shù)會(huì)獲得一個(gè) addrinfo 結(jié)構(gòu)的列表,調(diào)用的返回值是 addrinfo 的結(jié)構(gòu)(列表)指針。 ?????? 本文結(jié)合在 WinowsXP 和 Windows2003 Server 上使用該函數(shù)的經(jīng)驗(yàn),對(duì) getaddrinfo 函數(shù)和 addrinfo 數(shù)據(jù)結(jié)構(gòu)進(jìn)行介紹,并對(duì)其參數(shù)的設(shè)置加以討論,主要包括 nodename 和 servname 的取值對(duì)返回值的影響, hints 成員變量的設(shè)置對(duì)返回值的影響等。 可能有不完全或不準(zhǔn)確的地方,歡迎大家討論并指出。 1.getaddrinfo函數(shù)原型 函數(shù) 參數(shù)說(shuō)明 int getaddrinfo( const char* nodename const char* servname, const struct addrinfo* hints,// struct addrinfo** res ); nodename: 節(jié)點(diǎn)名可以是主機(jī)名,也可以是數(shù)字地址。( IPV4 的 10 進(jìn)點(diǎn)分,或是 IPV6 的 16 進(jìn)制) servname: 包含十進(jìn)制數(shù)的端口號(hào)或服務(wù)名如( ftp,http ) hints: 是一個(gè)空指針或指向一個(gè) addrinfo 結(jié)構(gòu)的指針,由調(diào)用者填寫(xiě)關(guān)于它所想返回的信息類(lèi)型的線索。 res: 存放返回 addrinfo 結(jié)構(gòu)鏈表的指針
Getaddrinfo 提供獨(dú)立于協(xié)議的名稱解析。 函數(shù)的前兩個(gè)參數(shù)分別是節(jié)點(diǎn)名和服務(wù)名。節(jié)點(diǎn)名可以是主機(jī)名,也可以是地址串 (IPv4 的點(diǎn)分十進(jìn)制數(shù)表示或 IPv6 的十六進(jìn)制數(shù)字串 ) 。服務(wù)名可以是十進(jìn)制的端口號(hào),也可以是已定義的服務(wù)名稱,如 ftp 、 http 等。注意:其中節(jié)點(diǎn)名和服務(wù)名都是可選項(xiàng),即節(jié)點(diǎn)名或服務(wù)名可以為 NULL ,此時(shí)調(diào)用的結(jié)果將取缺省設(shè)置,后面將詳細(xì)討論。 函數(shù)的第三個(gè)參數(shù) hints 是 addrinfo 結(jié)構(gòu)的指針,由調(diào)用者填寫(xiě)關(guān)于它所想返回的信息類(lèi)型的線索。函數(shù)的返回值是一個(gè)指向 addrinfo 結(jié)構(gòu)的鏈表指針 res 。 2.addrinfo結(jié)構(gòu) 結(jié)構(gòu) 固定的參數(shù) typedef struct addrinfo {? int ai_flags;? int ai_family;? int ai_socktype;? int ai_protocol;? size_t ai_addrlen;? char* ai_canonname;? struct sockaddr* ai_addr;? struct addrinfo* ai_next; } ai_addrlen must be zero or a null pointer ai_canonname must be zero or a null pointer ai_addr must be zero or a null pointer ai_next must be zero or a null pointer 可以改動(dòng)的參數(shù) ai_flags:AI_PASSIVE,AI_CANONNAME,AI_NUMERICHOST ai_family: AF_INET,AF_INET6 ai_socktype: SOCK_STREAM,SOCK_DGRAM ai_protocol: IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc.
3 參數(shù)說(shuō)明 在 getaddrinfo 函數(shù)之前通常需要對(duì)以下 6 個(gè)參數(shù)進(jìn)行以下設(shè)置: nodename 、 servname 、 hints 的 ai_flags 、 ai_family 、 ai_socktype 、 ai_protocol 在 6 項(xiàng)參數(shù)中,對(duì)函數(shù)影響最大的是 nodename , sername 和 hints.ai_flag 而 ai_family 只是有地址為 v4 地址或 v6 地址的區(qū)別。而 ai_protocol 一般是為 0 不作改動(dòng)。 其中 ai_flags 、 ai_family 、 ai_socktype 說(shuō)明如下: 參數(shù) 取值 值 說(shuō)明 ai_family AF_INET 2 IPv4 AF_INET6 23 IPv6 AF_UNSPEC 0 協(xié)議無(wú)關(guān) ai_protocol IPPROTO_IP 0 IP 協(xié)議 IPPROTO_IPV4 4 IPv4 IPPROTO_IPV6 41 IPv6 IPPROTO_UDP 17 UDP IPPROTO_TCP 6 TCP ai_socktype SOCK_STREAM 1 流 SOCK_DGRAM 2 數(shù)據(jù)報(bào) ai_flags AI_PASSIVE 1 被動(dòng)的,用于 bind ,通常用于 server socket AI_CANONNAME 2 AI_NUMERICHOST 4 地址為數(shù)字串
對(duì)于 ai_flags 值的說(shuō)明: AI_NUMERICHOST AI_CANONNAME AI_PASSIVE 0/1 0/1 0/1
如上表所示, ai_flagsde 值范圍為 0~7 ,取決于程序如何設(shè)置 3 個(gè)標(biāo)志位,比如設(shè)置 ai_flags 為 ?“AI_PASSIVE|AI_CANONNAME” , ai_flags 值就為 3 。三個(gè)參數(shù)的含義分別為: (1)AI_PASSIVE 當(dāng)此標(biāo)志置位時(shí),表示調(diào)用者將在 bind() 函數(shù)調(diào)用中使用返回的地址結(jié)構(gòu)。當(dāng)此標(biāo)志不置位時(shí),表示將在 connect() 函數(shù)調(diào)用中使用。 當(dāng)節(jié)點(diǎn)名位 NULL ,且此標(biāo)志置位,則返回的地址將是通配地址。 如果節(jié)點(diǎn)名 NULL ,且此標(biāo)志不置位,則返回的地址將是回環(huán)地址。 (2)AI_CANNONAME 當(dāng)此標(biāo)志置位時(shí),在函數(shù)所返回的第一個(gè) addrinfo 結(jié)構(gòu)中的 ai_cannoname 成員中,應(yīng)該包含一個(gè)以空字符結(jié)尾的字符串,字符串的內(nèi)容是節(jié)點(diǎn)名的正規(guī)名。 (3)AI_NUMERICHOST 當(dāng)此標(biāo)志置位時(shí),此標(biāo)志表示調(diào)用中的節(jié)點(diǎn)名必須是一個(gè)數(shù)字地址字符串。 4.實(shí)際使用的幾種常用設(shè)置 一般情況下, client/server 編程中, server 端調(diào)用 bind (如果面向連接的還需要 listen ), client 則不用掉 bind 函數(shù),解析地址后直接 connect (面向連接)或直接發(fā)送數(shù)據(jù)(無(wú)連接)。因此,比較常見(jiàn)的情況有 (1)?????? 通常服務(wù)器端在調(diào)用 getaddrinfo 之前, ai_flags 設(shè)置 AI_PASSIVE ,用于 bind ;主機(jī)名 nodename 通常會(huì)設(shè)置為 NULL ,返回通配地址 [::] 。 (2)?????? 客戶端調(diào)用 getaddrinfo 時(shí), ai_flags 一般不設(shè)置 AI_PASSIVE ,但是主機(jī)名 nodename 和服務(wù)名 servname (更愿意稱之為端口)則應(yīng)該不為空。 (3)?????? 當(dāng)然,即使不設(shè)置 AI_PASSIVE ,取出的地址也并非不可以被 bind ,很多程序中 ai_flags 直接設(shè)置為 0 ,即 3 個(gè)標(biāo)志位都不設(shè)置,這種情況下只要 hostname 和 servname 設(shè)置的沒(méi)有問(wèn)題就可以正確 bind 。 上述情況只是簡(jiǎn)單的 client/server 中的使用,但實(shí)際在使用 getaddrinfo 和參考國(guó)外開(kāi)源代碼的時(shí)候,曾遇到一些將 servname (即端口)設(shè)為 NULL 的情況 ( 當(dāng)然,此時(shí) nodename 必不為 NULL ,否則調(diào)用 getaddrinfo 會(huì)報(bào)錯(cuò) ) 。以下分情況進(jìn)行了測(cè)試: (1)?????? 如果 nodename 是字符串型的 IPv6 地址, bind 的時(shí)候會(huì)分配臨時(shí)端口; (2)?????? 如果 nodename 是本機(jī)名, servname 為 NULL ,則根據(jù)操作系統(tǒng)的不同略有不同,本文僅在 WinXP 和 Win2003 上作了測(cè)試。 a)???????? WinXP 系統(tǒng)( SP2 )返回 loopback 地址 [::1] b)??????? Win2003 則將本機(jī)的所有 IPv6 地址列表加以返回。因?yàn)橥ǔR慌_(tái) IPv6 主機(jī)都有可能不止一個(gè) IPv6 地址,比如 fe80::1 (本機(jī) loopback 地址)、 fe80::*** 的 Link-Local 地址、 3ffe:*** 的全局地址等等。這種情況下調(diào)用 getaddrinfo 會(huì)將這些地址全部返回,調(diào)用者應(yīng)該注意如何使用這些地址。另外要注意的是,對(duì)于 fe80:: 的地址在綁定的時(shí)候必須標(biāo)明接口地址,即使用 fe80::20d:60ff:fe78:51c2%4 或 fe80::1%1 這樣的地址格式,通過(guò) getaddrinfo 直接取出 fe80 地址好像無(wú)法直接 bind 。 5.幾句廢話 在 Windows 環(huán)境調(diào)試 IPv6 的程序個(gè)人感覺(jué)還是使用 WinXP ( SP2 )和 Win2003 基本上沒(méi)有太大的區(qū)別,使用 Win2003 更規(guī)范一些。 用 VC 編寫(xiě)和調(diào)試 IPv6 的程序一定要安裝 Windows 較新的 SDK ,我安裝的是 MS_Platform_SDK_Feb_2003 ,否則庫(kù)函數(shù)和頭文件可能都會(huì)有問(wèn)題。 ? [ 參考 ] [1]MSDN Library – January 2 004 ms-help://MS.MSDNQTR.2004JAN.1033/winsock/winsock/getaddrinfo_2.htm ms-help://MS.MSDNQTR.2004JAN.1033/winsock/winsock/addrinfo_2.htm [2] 《理解IPv6》("Understanding IPv6”),清華大學(xué)出版社 以上測(cè)試結(jié)果恐有不完善和錯(cuò)誤的地方,歡迎大家指正,本人聯(lián)系方式:wjb@nlsde.buaa.edu.cn 王劍白
總結(jié)
以上是生活随笔 為你收集整理的IPv6名称到地址的转换函数getaddrinfo()详解 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。