在名字和數(shù)值地址間進(jìn)行轉(zhuǎn)換的函數(shù):
gethostbyname和gethostbyaddr:在主機(jī)名字與ipv4地址之間進(jìn)行轉(zhuǎn)換。僅僅支持IPv4.
getservbyname和getservbyport:在服務(wù)名字和端口號之間進(jìn)行轉(zhuǎn)換。
getaddrinfo和getnameinfo:用于主機(jī)名字和IP地址之間以及服務(wù)名字和端口號之間的轉(zhuǎn)換。(這兩個函數(shù)是協(xié)議無關(guān)的)
域名系統(tǒng)(Domain Name System,簡稱DNS)主要用于主機(jī)名字和IP地址之間的映射。
資源記錄
DNS中的條目稱為資源記錄(resource record,簡稱RR)。
RR類型:
A A記錄把一個主機(jī)名映射成一個32位的IPv4地址。
AAAA AAAA記錄把一個主機(jī)名映射成一個128位的IPv6地址。
PTR 稱為“指針記錄(pointer record)”,它把IP地址映射成主機(jī)名。
解析器和名字服務(wù)器
每個組織機(jī)構(gòu)往往運(yùn)行一個或多個名字服務(wù)器(name server),它們通常就是所謂的BIND(Berkeley Internet Name Domain)程序。應(yīng)用程序通過調(diào)用稱為解析器(resolver)的函數(shù)庫中的函數(shù)接觸DNS服務(wù)器。常見的解析器函數(shù)是gethostbyname和gethostbyaddr:前者把主機(jī)名映射成IPv4地址,后者則執(zhí)行相反的映射。
下圖展示了應(yīng)用進(jìn)程、解析器和名字服務(wù)器之間的一個典型關(guān)系。

解析器代碼通過讀取其系統(tǒng)相關(guān)配置文件確定本組織機(jī)構(gòu)的名字服務(wù)器們(為可靠和冗余的目的,大多數(shù)組織機(jī)構(gòu)運(yùn)行多個名字服務(wù)器)的所在位置。文件/etc/resolv.conf通常包含本地名字服務(wù)器主機(jī)的IP地址。
DNS替代方法
不使用DNS也可能獲取名字和地址信息。常用的替代方法有靜態(tài)主機(jī)文件(通常是/etc/hosts文件)、網(wǎng)絡(luò)信息系統(tǒng)(Network Information System,簡稱NIS)以及輕權(quán)目錄訪問協(xié)議(Lightweight Directory access PRotocol,簡稱LDAP)。
查找主機(jī)名最基本的函數(shù)是gethostbyname。如果調(diào)用成功,它就返回一個指向hostent結(jié)構(gòu)的指針,該結(jié)構(gòu)中含有所查找主機(jī)的所有IPv4地址。這個函數(shù)的局限是只能返回IPv4地址,而getaddrinfo函數(shù)能夠同時處理IPv4地址和IPv6地址。
#include <netdb.h>struct hostent *gethostbyname(const char *hostname);返回值:非空指針——成功;空指針——出錯,同時設(shè)置h_errno
本函數(shù)返回的非空指針指向如下的hostent結(jié)構(gòu):
struct hostent { char *h_name; /* official(canonical) name of host */ char **h_aliases; /* pointer to array of pointers to alias names */ int h_addrtype; /* host address type: AF_INET */ int h_length; /* length of address: 4 */ char **h_addr_list; /* ptr to array of ptrs with IPv4 addrs */};
gethostbyname與其他套接口函數(shù)的不同之處在于:當(dāng)發(fā)生錯誤時,它不設(shè)置errno變量,而是將全局整數(shù)變量h_errno設(shè)置在頭文件<netdb.h>中定義的下列常值之一:
HOST_NOT_FOUND
TRY_AGAIN
NO_RECOVERY
NO_DATA(等同于NO_ADDRESS)
多數(shù)解析器提供名為hstrerror的函數(shù),它以某個h_errno值作為唯一的參數(shù),返回的是一個const char *指針,指向相應(yīng)錯誤的說明。
gethostbyaddr函數(shù)試圖由一個二進(jìn)制IP地址找到相應(yīng)的主機(jī)名,與gethostbyname的行為剛好相反。
#include <netdb.h>struct hostent *gethostbyaddr(const char *addr, socklen_t len, int family);返回值:非空指針——成功;空指針——出錯,同時設(shè)置h_errno
本函數(shù)返回一個同樣指向hostent結(jié)構(gòu)的指針。
addr參數(shù)實際上不是char *類型,而是一個指向存放IPv4地址的某個in_addr結(jié)構(gòu)的指針;
len參數(shù)是這個結(jié)構(gòu)的大?。簩τ贗Pv4地址為4;
family參數(shù)為AF_INET。
服務(wù)也通??棵謥碚J(rèn)知。如果我們在程序代碼中通過其名字而不是端口號來指代一個服務(wù),而且從名字到端口號的映射關(guān)系保存在一個文件中(通常是/etc/services),那么即使端口號發(fā)生變動,我們需修改的僅僅是/etc/services文件中的某一行,而不必重新編譯應(yīng)用程序。
getservbyname函數(shù)用于根據(jù)給定的名字查找相應(yīng)服務(wù)。
#include <netdb.h>struct servent *getservbyname(const char *servname, const char *protoname);返回:非空指針——成功;空指針——出錯
本函數(shù)返回的非空指針指向如下的servent結(jié)構(gòu):
struct servent { char *s_name; /* official service name */ char **s_aliases; /* alias list */ int s_port; /* port number, network-byte order */ char *s_proto; /* protocol to use */};服務(wù)名參數(shù)servname必須指定。如果同時指定了協(xié)議(即protoname參數(shù)為非空指針),那么指定服務(wù)必須有匹配的協(xié)議。有些因特網(wǎng)服務(wù)既用TCP也用UDP提供(例如DNS),其他因特網(wǎng)服務(wù)則僅僅支持單個協(xié)議(例如FTP要求使用TCP)。如果protoname未指定而servname指定服務(wù)支持多個協(xié)議,那么返回哪個端口號取決于實現(xiàn)。
servent結(jié)構(gòu)中我們關(guān)心的主要是端口號。既然端口號是以網(wǎng)絡(luò)字節(jié)序返回的,把它存放到套接口地址結(jié)構(gòu)時絕不能調(diào)用htons。
本函數(shù)的典型調(diào)用如下:
struct servent *sptr;sptr = getservbyname("domain", "udp");sptr = getservbyname("ftp", "tcp");getservbyport函數(shù)用于根據(jù)給定端口號和可選協(xié)議查找相應(yīng)服務(wù)。
#include <netdb.h>struct servent *getservbyport(int port, const char *protoname);返回:非空指針——成功;空指針——出錯
port參數(shù)的值必須為網(wǎng)絡(luò)字節(jié)序。本函數(shù)的典型調(diào)用如下:
struct servent *sptr;sptr = getservbyport(htons(53), "udp");sptr = getservbyport(htons(21), "tcp");
getaddrinfo函數(shù)能夠處理名字到地址以及服務(wù)到端口這兩種轉(zhuǎn)換,它解決了把主機(jī)名和服務(wù)名轉(zhuǎn)換成套接口地址結(jié)構(gòu)的問題,返回的是一個sockaddr結(jié)構(gòu)的鏈表而不是一個地址清單。這些sockaddr結(jié)構(gòu)隨后可由套接口函數(shù)直接使用。
#include <netdb.h>int getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result);返回:0——成功;非0——出錯
本函數(shù)通過result指針參數(shù)返回一個指向addrinfo結(jié)構(gòu)鏈表的指針,而addrinfo結(jié)構(gòu)定義在頭文件<netdb.h>中:
struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* AF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ socklen_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* ptr to canonical name for host */ struct sockaddr *ai_addr; /* ptr to socket address structure */ struct addrinfo *ai_next; /* ptr to next structure in linked list */};其中,
hostname參數(shù)是一個主機(jī)名或地址串(IPv4的點(diǎn)分十進(jìn)制數(shù)串或IPv6的十六進(jìn)制數(shù)串)。
service參數(shù)是一個服務(wù)名或十進(jìn)制端口號數(shù)串。
hints參數(shù)可以是一個空指針,也可以是一個指向某個addrinfo結(jié)構(gòu)的指針,調(diào)用者在這個結(jié)構(gòu)中填入關(guān)于期望返回的信息類型的暗示。
hints結(jié)構(gòu)中調(diào)用者可以設(shè)置的成員有:
其中ai_flags成員可用的標(biāo)志值及其含義如下:
AI_PASSIVE 套接口將用于被動打開。
AI_CANONNAME 告知getaddrinfo函數(shù)返回主機(jī)的規(guī)范名字。
AI_NUMERICHOST 防止任何類型的名字到地址映射;hostname參數(shù)必須是一個地址串。
AI_NUMERICSERV 防止任何類型的名字到服務(wù)映射;service參數(shù)必須是一個十進(jìn)制端口號數(shù)串。
AI_V4MAPPED 如果同時指定ai_family成員的值為AF_INET6, 那么如果沒有可用的AAAA記錄,就返回與A記錄對應(yīng)的IPv4映射的IPv6地址。
AI_ALL 如果同時指定AI_V4MAPPED標(biāo)志,那么除了返回與AAAA記錄對應(yīng)的IPv6地址外,還返回與A記錄對應(yīng)的IPv4映射的IPv6地址。
AI_ADDRCONFIG 按照所在主機(jī)的配置選擇返回地址類型,也就是只查找與所在主機(jī)回饋接口以外的網(wǎng)絡(luò)接口配置的IP地址版本一致的地址。
如果hints參數(shù)是一個空指針,本函數(shù)就假設(shè)ai_flags、ai_sokctype和ai_protocol的值均為0,ai_family的值為AF_UNSPEC。
如果本函數(shù)返回成功(0),那么由result參數(shù)指向的變量已被填入一個指針,它指向的是由其中的ai_next成員串接起來的addrinfo結(jié)構(gòu)鏈表??蓪?dǎo)致返回多個addrinfo結(jié)構(gòu)的情形有以下兩個:
如果與hostname參數(shù)關(guān)聯(lián)的地址有多個,那么適用于所請求地址族(可通過hints結(jié)構(gòu)的ai_family成員設(shè)置)的每個地址都返回一個對應(yīng)的結(jié)構(gòu)。
如果service參數(shù)指定的服務(wù)支持多個套接口類型,那么每個套接口類型都可能返回一個對應(yīng)的結(jié)構(gòu),具體取決于hints結(jié)構(gòu)的ai_socktype成員。
getnameinfo是getaddrinfo的互補(bǔ)函數(shù):它以一個套接口地址為參數(shù),返回描述其中的主機(jī)的一個字符串和描述其中的服務(wù)的另一個字符串。本函數(shù)以協(xié)議無關(guān)的方式提供這些信息;也就是說,調(diào)用者不必關(guān)心存放在套接口地址結(jié)構(gòu)中的協(xié)議地址的類型。
#include <netdb.h>int getnameinfo(const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);返回:0——成功,非0——出錯
sockaddr指向一個套接口地址結(jié)構(gòu)。
待返回的2個直觀可讀的字符串由調(diào)用者預(yù)先分配存儲空間:host和hostlen指定主機(jī)字符串;serv和servlen指定服務(wù)字符串。如果調(diào)用者不想返回主機(jī)字符串,那就指定hostlen為0。同樣,把servlen指定為0就是不想返回服務(wù)字符串。頭文件<netdb.h>中定義了2個常值用于分配這兩個存儲空間:NI_MAXHOST給出主機(jī)字符串存儲空間的最大長度,值為1025;NI_MAXSERV給出服務(wù)字符串存儲空間的最大長度,值為32.
6個可指定的標(biāo)志flags,用于改變getnameinfo的操作:
| 常值 | 說明 |
| NI_DGRAM NI_NAMEREQD NI_NOFQDN NI_NUMERICHOST NI_NUMERICSCOPE NI_NUMERICSERV | 數(shù)據(jù)報服務(wù) 若不能從地址解析出名字則返回錯誤 只返回FQDN的主機(jī)名部分 以數(shù)串格式返回主機(jī)字符串 以數(shù)串格式返回范圍標(biāo)識字符串 以數(shù)串格式返回服務(wù)字符串 |
四類網(wǎng)絡(luò)相關(guān)信息總結(jié)如下表:
| 信息 | 數(shù)據(jù)文件 | 結(jié)構(gòu) | 鍵值查找函數(shù) |
| 主機(jī) 網(wǎng)絡(luò) 協(xié)議 服務(wù) | /etc/hosts /etc/networks /etc/protocols /etc/services | hostent netent protoent servent | gethostbyaddr,gethostbyname getnetbyaddr,getnetbyname getprotobyname,getprotobynumber getservbyname,getservbyport |
新聞熱點(diǎn)
疑難解答