UNP Chapter 9 - 基本名字与地址转换
9.1. 概述
本章講述在名字和數值地址間進行轉換的函數:gethostbyname和gethostbyaddr在主機名字與IP地址間進行轉換,getservbyname和getservbyport在服務器名字和端口號間進行轉換。
9.2. 域名系統
DNS(Domain Name System)主要用于主機名與IP地址間的映射。主機名可以是簡單名字,如solaris或bsdi,也可以是全限定域名FQDN(Fully Qualified Domain Name),如solaris.kohala.com
DNS中的條目稱為資源記錄RR(resource record):
A??????? --? A記錄將主機名映射為32位的IPv4地址。
AAAA? --? AAAA記錄將主機名映射為128位的IPv6地址。
PTR??? --? PTR記錄(稱為"指針記錄")將IP地址映射為主機名。對于IPv4地址,32位地址的四個字節順序反轉,每個字節都轉換成他的十進制ASCII值(0~255),然后附上in-addr.arpa,結果串用于PTR查詢。對于IPv6地址,128位地址中的32個4位組順序發轉,每組被轉換成相應的十六進制ASCII值(0~9, a~f),并附上ip6.int。
MX???? --? MX記錄指定一主機作為某主機的“郵件交換器”。
CNAME -- CNAME代表“canonical name(規范名字)”,其常見的用法是為常用服務如ftp和www指派一個CNAME記錄。
?
解析器和名字服務器
組織運行一個或多個名字服務器(name server), 它們通常就是所謂的BIND(Berkeley Internet Name Domain)程序。各種應用程序,如本書中我們編寫的客戶和服務器程序,通過調用稱為解析器(resolver)的庫中的函數來與DNS服務器聯系。最常見的解析器函數是gethostbyname和gethostbyaddr。
文件/etc/resolv.conf一般包含本地名字服務器的IP地址。
?
DNS替代方法
不使用DNS也可以得到名字和地址信息,最常用的替代方法為靜態主機文件(一般為文件/etc/hosts)或網絡信息系統NIS(Network Information System)。
?
9.3. gethostbyname函數
#include <netdb.h>struct hostent * gethostbyname(const char * hostname); // 返回: 非空指針-成功, 空指針-出錯,同時設置h_errno
此函數返回的非空指針指向下面的hostent結構:
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與我們所介紹的其他套接口函數不同之處在于:當發生錯誤時,他不設置errno,而是將全局整數h_errno設置為定義在頭文件<netdb.h>中的下列常值中的一個:
HOST_NOT_FOUND
TRY_AGAIN
NO_RECOVERTY
NO_DATA(等同于NO_ADDRESS) 表示指定的名字有效,但它既沒有A記錄,也沒有AAAA記錄。只有MX記錄的主機名就是這樣的例子。
下面是一個調用gethostbyname的簡單例子,它可有任意數目的命令行參數,輸出所有返回的信息:
#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解析器選項
9.5. gethostbyname2函數與IPv6支持
#include <netdb.h>struct hostent * gethostbyname2(const char * hostname, int family); //返回:非空指針-成功,空指針-出錯 同時設置h_errno
描述函數gethostbyname和選項RES_USE_INET6的行為的一個方法是看看它的源代碼
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函數
#include <netdb.h>struct hostent * gethostbyaddr(const char * addr, size_t len, int family); //返回:非空指針-成功,空指針-出錯 同時設置h_errno
9.7. uname函數
#include <sys/utsname.h>int uname(struct utsname * name); // 返回:非負值-成功,-1-出錯
此函數裝填結構utsname,其地址由調用者傳遞:
#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 */
};
為了確定本地主機的IP地址,我們調用uname以得到主機名字,然后調用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);
}
函數返回值是結構hostent的成員h_addr_list,即指向IP地址的指針數組。我們還通過指針參數返回地址族。
?
9.8. gethostname函數
#include <unistd.h>int gethostname(char * name, size_t namelen); //返回:0-成功,-1-出錯
name是指向主機名存儲位置的指針,namelen是此數組的大小。
?
9.9. getservbyname和getservbyport函數
服務器就像主機一樣,也常常是由名字來標識的。
#include <netdb.h>struct servent * getservbyname(const char * servname, const char * protoname); //返回: 非空指針-成功,空指針-出錯
此函數返回一個指向下面所示結構的指針:
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 */
};
服務名servname必須指定,如果還指定了一個協議(即protoname為非空指針),則結果表項也必須有匹配的協議。結構servent中我們關心的主要成員是端口號。由于端口號是以網絡字節序返回的,在將它存儲于套接口地址結構時,絕對不能調用htons,對此函數的典型調用是:
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 */
在給定端口號和可選協議后可以使用getservbyport函數查找相應的服務:
#include <netdb.h>struct servent * getservbyport(int port, const char * protname); //返回:非空指針-成功,空指針-出錯
port值必須為網絡字節序,對此函數的典型調用是:
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,由于沒有服務使用端口21,所以最后一個調用將失敗。
9.10?其它網絡相關信息
9.11. 小結
轉載于:https://www.cnblogs.com/s7vens/archive/2012/01/18/2325658.html
總結
以上是生活随笔為你收集整理的UNP Chapter 9 - 基本名字与地址转换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MFC添加背景图片方法
- 下一篇: Qt显示中文ansi字符串乱码问题解决方