日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

getaddrinfo()函數(shù)詳解

系統(tǒng) 3586 0

getaddrinfo()函數(shù)詳解

?

1. 概述

IPv4中使用 gethostbyname()函數(shù) 完成主機(jī)名到地址解析,這個函數(shù)僅僅支持IPv4,且不允許調(diào)用者指定所需地址類型的任何信息,返回的結(jié)構(gòu)只包含了用于存儲IPv4地址的空間。IPv6中引入了getaddrinfo()的新API,它是協(xié)議無關(guān)的,既可用于IPv4也可用于IPv6。getaddrinfo函數(shù)能夠處理名字到地址以及服務(wù)到端口這兩種轉(zhuǎn)換,返回的是一個addrinfo的結(jié)構(gòu)(列表)指針而不是一個地址清單。這些addrinfo結(jié)構(gòu)隨后可由套接口函數(shù)直接使用。如此以來,getaddrinfo函數(shù)把協(xié)議相關(guān)性安全隱藏在這個庫函數(shù)內(nèi)部。應(yīng)用程序只要處理由getaddrinfo函數(shù)填寫的套接口地址結(jié)構(gòu)。該函數(shù)在 POSIX規(guī)范中定義了。


2. 函數(shù)說明

包含頭文件
#include<netdb.h>

函數(shù)原型
int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );

參數(shù)說明
hostname:一個主機(jī)名或者地址串(IPv4的點(diǎn)分十進(jìn)制串或者IPv6的16進(jìn)制串)
service:服務(wù)名可以是十進(jìn)制的端口號,也可以是已定義的服務(wù)名稱,如ftp、http等
hints:可以是一個空指針,也可以是一個指向某個 addrinfo結(jié)構(gòu)體 的指針,調(diào)用者在這個結(jié)構(gòu)中填入關(guān)于期望返回的信息類型的暗示。舉例來說:如果指定的服務(wù)既支持TCP也支持UDP,那么調(diào)用者可以把hints結(jié)構(gòu)中的ai_socktype成員設(shè)置成SOCK_DGRAM使得返回的僅僅是適用于數(shù)據(jù)報(bào)套接口的信息。
result:本函數(shù)通過result指針參數(shù)返回一個指向addrinfo結(jié)構(gòu)體鏈表的指針。
返回值:0——成功,非0——出錯


3. 參數(shù)設(shè)置

在getaddrinfo函數(shù)之前通常需要對以下6個參數(shù)進(jìn)行以下設(shè)置:nodename、servname、hints的ai_flags、ai_family、ai_socktype、ai_protocol。
在6項(xiàng)參數(shù)中,對函數(shù)影響最大的是nodename,sername和hints.ai_flag,而ai_family只是有地址為v4地址或v6地址的區(qū)別。ai_protocol一般是為0不作改動。

getaddrinfo在實(shí)際使用中的幾種常用參數(shù)設(shè)置
一般情況下,client/server編程中,server端調(diào)用bind(如果面向連接的還需要listen),client則不用掉bind函數(shù),解析地址后直接connect(面向連接)或直接發(fā)送數(shù)據(jù)(無連接)。因此,比較常見的情況有
(1)??? 通常服務(wù)器端在調(diào)用getaddrinfo之前,ai_flags設(shè)置AI_PASSIVE,用于bind;主機(jī)名nodename通常會設(shè)置為NULL,返回通配地址[::]。
(2)??? 客戶端調(diào)用getaddrinfo時,ai_flags一般不設(shè)置AI_PASSIVE,但是主機(jī)名nodename和服務(wù)名servname(更愿意稱之為端口)則應(yīng)該不為空。
(3)??? 當(dāng)然,即使不設(shè)置AI_PASSIVE,取出的地址也并非不可以被bind,很多程序中ai_flags直接設(shè)置為0,即3個標(biāo)志位都不設(shè)置,這種情況下只要hostname和servname設(shè)置的沒有問題就可以正確bind。

上述情況只是簡單的client/server中的使用,但實(shí)際在使用getaddrinfo和參考國外開源代碼的時候,曾遇到一些將servname(即端口)設(shè)為NULL的情況(當(dāng)然,此時nodename必不為NULL,否則調(diào)用getaddrinfo會報(bào)錯)。
以下分情況進(jìn)行了測試:
(1)??? 如果nodename是字符串型的IPv6地址,bind的時候會分配臨時端口;
(2)??? 如果nodename是本機(jī)名,servname為NULL,則根據(jù)操作系統(tǒng)的不同略有不同,本文僅在WinXP和Win2003上作了測試。
??????? a)??? WinXP系統(tǒng)(SP2)返回loopback地址[::1]
??????? b)??? Win2003則將本機(jī)的所有IPv6地址列表加以返回。因?yàn)橥ǔR慌_IPv6主機(jī)都有可能不止一個IPv6地址,比如fe80::1(本機(jī) loopback地址)、fe80::***的Link-Local地址、3ffe:***的全局地址等等。這種情況下調(diào)用getaddrinfo會將這些地址全部返回,調(diào)用者應(yīng)該注意如何使用這些地址。另外要注意的是,對于fe80::的地址在綁定的時候必須標(biāo)明接口地址,即使用 fe80::20d:60ff:fe78:51c2%4或fe80::1%1這樣的地址格式,通過getaddrinfo直接取出fe80地址好像無法直接bind。
?? ??? ?
?? ??? ?
4. 使用細(xì)節(jié)

如果本函數(shù)返回成功,那么由result參數(shù)指向的變量已被填入一個指針,它指向的是由其中的ai_next成員串聯(lián)起來的addrinfo結(jié)構(gòu)鏈表。可以導(dǎo)致返回多個addrinfo結(jié)構(gòu)的情形有以下2個:
??? 1.??? 如果與hostname參數(shù)關(guān)聯(lián)的地址有多個,那么適用于所請求地址簇的每個地址都返回一個對應(yīng)的結(jié)構(gòu)。
??? 2.??? 如果service參數(shù)指定的服務(wù)支持多個套接口類型,那么每個套接口類型都可能返回一個對應(yīng)的結(jié)構(gòu),具體取決于hints結(jié)構(gòu)的ai_socktype成員。

我們必須先分配一個hints結(jié)構(gòu),把它清零后填寫需要的字段,再調(diào)用getaddrinfo,然后遍歷一個鏈表逐個嘗試每個返回地址。
?? ??? ?
getaddrinfo解決了把主機(jī)名和服務(wù)名轉(zhuǎn)換成套接口地址結(jié)構(gòu)的問題。

其中,如果getaddrinfo出錯,那么返回一個非0的錯誤值。
#include<netdb.h>
const char *gai_strerror( int error );
該函數(shù)以getaddrinfo返回的非0錯誤值的名字和含義為他的唯一參數(shù),返回一個指向?qū)?yīng)的出錯信息串的指針。

由getaddrinfo返回的所有存儲空間都是動態(tài)獲取的,這些存儲空間必須通過調(diào)用freeaddrinfo返回給系統(tǒng)。
#include< netdb.h >
void freeaddrinfo( struct addrinfo *ai );
ai參數(shù)應(yīng)指向由getaddrinfo返回的第一個addrinfo結(jié)構(gòu)。這個連表中的所有結(jié)構(gòu)以及它們指向的任何動態(tài)存儲空間都被釋放掉。


5. 例子

代碼
#include? < stdio.h >
#include?
< stdlib.h >
#include?
< sys / socket.h >
#include?
< netinet / in .h >
#include?
< netdb.h >
#include?
< string .h >
int ?main( int ?argc,? char ? ** argv)
{
if ?(argc? != ? 2 )?{
fprintf(stderr,?
" Usage:?%s?hostname\n " ,
argv[
1 ]);
exit(
1 );???
}

struct ?addrinfo? * answer,?hint,? * curr;
char ?ipstr[ 16 ];???
bzero(
& hint,? sizeof (hint));
hint.ai_family?
= ?AF_INET;
hint.ai_socktype?
= ?SOCK_STREAM;

int ?ret? = ?getaddrinfo(argv[ 1 ],?NULL,? & hint,? & answer);
if ?(ret? != ? 0 )?{
fprintf(stderr,
" getaddrinfo:?&s\n " ,
gai_strerror(ret));
exit(
1 );
}

for ?(curr? = ?answer;?curr? != ?NULL;?curr? = ?curr -> ai_next)?{
inet_ntop(AF_INET,
& ((( struct ?sockaddr_in? * )(curr -> ai_addr)) -> sin_addr),
ipstr,?
16 );
printf(
" %s\n " ,?ipstr);
}

freeaddrinfo(answer);
exit(
0 );
}


?

getaddrinfo()函數(shù)詳解


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 砚山县| 连江县| 岐山县| 治县。| 樟树市| 上栗县| 屏东市| 赤水市| 临沂市| 闸北区| 霸州市| 丰都县| 万盛区| 青岛市| 清苑县| 云浮市| 兴海县| 梓潼县| 玛多县| 吴旗县| 缙云县| 荔波县| 潼关县| 怀柔区| 白山市| 东阳市| 韶山市| 始兴县| 武定县| 东城区| 阿克陶县| 盐城市| 克东县| 永新县| 淮南市| 保定市| 麻江县| 灯塔市| 汾阳市| 玛曲县| 涪陵区|