UNP Chapter 9 - 基本名字与地址转换
9.1. 概述
本章講述在名字和數(shù)值地址間進(jìn)行轉(zhuǎn)換的函數(shù):gethostbyname和gethostbyaddr在主機(jī)名字與IP地址間進(jìn)行轉(zhuǎn)換,getservbyname和getservbyport在服務(wù)器名字和端口號間進(jìn)行轉(zhuǎn)換。
9.2. 域名系統(tǒng)
DNS(Domain Name System)主要用于主機(jī)名與IP地址間的映射。主機(jī)名可以是簡單名字,如solaris或bsdi,也可以是全限定域名FQDN(Fully Qualified Domain Name),如solaris.kohala.com
DNS中的條目稱為資源記錄RR(resource record):
A??????? --? A記錄將主機(jī)名映射為32位的IPv4地址。
AAAA? --? AAAA記錄將主機(jī)名映射為128位的IPv6地址。
PTR??? --? PTR記錄(稱為"指針記錄")將IP地址映射為主機(jī)名。對于IPv4地址,32位地址的四個(gè)字節(jié)順序反轉(zhuǎn),每個(gè)字節(jié)都轉(zhuǎn)換成他的十進(jìn)制ASCII值(0~255),然后附上in-addr.arpa,結(jié)果串用于PTR查詢。對于IPv6地址,128位地址中的32個(gè)4位組順序發(fā)轉(zhuǎn),每組被轉(zhuǎn)換成相應(yīng)的十六進(jìn)制ASCII值(0~9, a~f),并附上ip6.int。
MX???? --? MX記錄指定一主機(jī)作為某主機(jī)的“郵件交換器”。
CNAME -- CNAME代表“canonical name(規(guī)范名字)”,其常見的用法是為常用服務(wù)如ftp和www指派一個(gè)CNAME記錄。
?
解析器和名字服務(wù)器
組織運(yùn)行一個(gè)或多個(gè)名字服務(wù)器(name server), 它們通常就是所謂的BIND(Berkeley Internet Name Domain)程序。各種應(yīng)用程序,如本書中我們編寫的客戶和服務(wù)器程序,通過調(diào)用稱為解析器(resolver)的庫中的函數(shù)來與DNS服務(wù)器聯(lián)系。最常見的解析器函數(shù)是gethostbyname和gethostbyaddr。
文件/etc/resolv.conf一般包含本地名字服務(wù)器的IP地址。
?
DNS替代方法
不使用DNS也可以得到名字和地址信息,最常用的替代方法為靜態(tài)主機(jī)文件(一般為文件/etc/hosts)或網(wǎng)絡(luò)信息系統(tǒng)NIS(Network Information System)。
?
9.3. gethostbyname函數(shù)
#include <netdb.h>struct hostent * gethostbyname(const char * hostname); // 返回: 非空指針-成功, 空指針-出錯,同時(shí)設(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 or AF_INET6 */
int h_length; /* length of address: 4 or 16 */
char * * h_addr_list; /* ptr to array of ptrs with IPv4 or IPv6 addrs */
};
#define h_addr h_addr_list[0] /* first address in list */
gethostbyname與我們所介紹的其他套接口函數(shù)不同之處在于:當(dāng)發(fā)生錯誤時(shí),他不設(shè)置errno,而是將全局整數(shù)h_errno設(shè)置為定義在頭文件<netdb.h>中的下列常值中的一個(gè):
HOST_NOT_FOUND
TRY_AGAIN
NO_RECOVERTY
NO_DATA(等同于NO_ADDRESS) 表示指定的名字有效,但它既沒有A記錄,也沒有AAAA記錄。只有MX記錄的主機(jī)名就是這樣的例子。
下面是一個(gè)調(diào)用gethostbyname的簡單例子,它可有任意數(shù)目的命令行參數(shù),輸出所有返回的信息:
#include "unp.h"int main(int argc, char * * argv)
{
char * ptr, * * pptr;
char str[INET6_ADDRSTRLEN];
struct hostent * hptr;
while(--argc > 0)
{
ptr = * ++argv;
if((hptr = gethostbyname(ptr)) == NULL)
{
err_msg("gethostbyname error for host: %s: %s", ptr, hstrerror(h_errno));
continue;
}
printf("official hostname: %s \n", hptr->h_name);
for(pptr = hptr->h_aliases; * pptr != NULL; pptr++)
printf("\t alias: %s \n", *pptr);
switch(hptr->h_addrtype)
{
case AF_INET:
#ifdef AF_INET6:
case AF_INET6:
#endif
pptr = hptr->h_addr_list;
for( ; * pptr != NULL; pptr++)
printf("\t address: %s \n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
break;
default:
err_ret("unknown address type");
break;
}
}
exit(0);
}
?
9.4. RES_USE_INET6解析器選項(xiàng)
9.5. gethostbyname2函數(shù)與IPv6支持
#include <netdb.h>struct hostent * gethostbyname2(const char * hostname, int family); //返回:非空指針-成功,空指針-出錯 同時(shí)設(shè)置h_errno
描述函數(shù)gethostbyname和選項(xiàng)RES_USE_INET6的行為的一個(gè)方法是看看它的源代碼
struct hostent * gethostbyname(const char * name){
struct hostent * hp;
if((_res.options & RES_INIT) == 0 && res_init() == -1)
{
h_errno = NETDB_INTERNAL;
return (NULL);
}
if(_res.options & RES_USE_INET6)
{
hp = gethostbyname2(name, AF_INET6);
if(hp)
return (hp);
}
return (gethostbyname2(name, AF_INET));
}
?
9.6. gethostbyaddr函數(shù)
#include <netdb.h>struct hostent * gethostbyaddr(const char * addr, size_t len, int family); //返回:非空指針-成功,空指針-出錯 同時(shí)設(shè)置h_errno
9.7. uname函數(shù)
#include <sys/utsname.h>int uname(struct utsname * name); // 返回:非負(fù)值-成功,-1-出錯
此函數(shù)裝填結(jié)構(gòu)utsname,其地址由調(diào)用者傳遞:
#define UTS_NAMESIZE 16#define UTS_NODESIZE 256
struct utsname
{
char sysname[_UTS_NAMESIZE]; /* name of this operating system */
char nodename[_UTS_NODESIZE]; /* name of this node */
char release[_UTS_NAMESIZE]; /* O.S release level */
char version[_UTS_NAMESIZE]; /* O.S version level */
char machine[_UTS_NAMESIZE]; /* hardware type */
};
為了確定本地主機(jī)的IP地址,我們調(diào)用uname以得到主機(jī)名字,然后調(diào)用gethostbyname以得到它的所有IP地址。
#include "unp.h"#include <sys/utsname.h>
char * * my_addrs(int * addrtype)
{
struct hostent * hptr;
struct utsname myname;
if(uname(&myname) < 0)
return(NULL);
if((hptr = gethostbyname(myname.nodename)) == NULL)
return(NULL);
*addrtype = hptr->h_addrtype;
return(hptr->h_addr_list);
}
函數(shù)返回值是結(jié)構(gòu)hostent的成員h_addr_list,即指向IP地址的指針數(shù)組。我們還通過指針參數(shù)返回地址族。
?
9.8. gethostname函數(shù)
#include <unistd.h>int gethostname(char * name, size_t namelen); //返回:0-成功,-1-出錯
name是指向主機(jī)名存儲位置的指針,namelen是此數(shù)組的大小。
?
9.9. getservbyname和getservbyport函數(shù)
服務(wù)器就像主機(jī)一樣,也常常是由名字來標(biāo)識的。
#include <netdb.h>struct servent * getservbyname(const char * servname, const char * protoname); //返回: 非空指針-成功,空指針-出錯
此函數(shù)返回一個(gè)指向下面所示結(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ù)名servname必須指定,如果還指定了一個(gè)協(xié)議(即protoname為非空指針),則結(jié)果表項(xiàng)也必須有匹配的協(xié)議。結(jié)構(gòu)servent中我們關(guān)心的主要成員是端口號。由于端口號是以網(wǎng)絡(luò)字節(jié)序返回的,在將它存儲于套接口地址結(jié)構(gòu)時(shí),絕對不能調(diào)用htons,對此函數(shù)的典型調(diào)用是:
sturct servent * sptr;sptr = getservbyname("domain", "udp"); /* DNS using UDP */
sptr = getservbyname("ftp", "tcp"); /* FTP using TCP */
sptr = getservbyname("ftp", NULL); /* FTP using TCP */
sptr = getservbyname("ftp", "udp"); /* this call will fall */
在給定端口號和可選協(xié)議后可以使用getservbyport函數(shù)查找相應(yīng)的服務(wù):
#include <netdb.h>struct servent * getservbyport(int port, const char * protname); //返回:非空指針-成功,空指針-出錯
port值必須為網(wǎng)絡(luò)字節(jié)序,對此函數(shù)的典型調(diào)用是:
struct servent * sptr;sptr = getservbyport(htons(53), "udp"); /* DNS using UDP */
sptr = getservbyport(htons(21), "tcp"); /* FTP using TCP */
sptr = getservbyport(htons(21), NULL); /* FTP using TCP */
sptr = getservbyport(htons(21), "udp"); /* this call will fail */
對于UDP,由于沒有服務(wù)使用端口21,所以最后一個(gè)調(diào)用將失敗。
9.10?其它網(wǎng)絡(luò)相關(guān)信息
9.11. 小結(jié)
轉(zhuǎn)載于:https://www.cnblogs.com/s7vens/archive/2012/01/18/2325658.html
總結(jié)
以上是生活随笔為你收集整理的UNP Chapter 9 - 基本名字与地址转换的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MFC添加背景图片方法
- 下一篇: Qt显示中文ansi字符串乱码问题解决方