第八章 主机名称与主机地址
来源:互联网 发布:office for mac通用 编辑:程序博客网 时间:2024/04/29 23:42
第八章 主机名称与主机地址
8.1 主机名称与主机地址解析
将主机名称解析映射到主机地址的过程称为主机名称解析。相反地,将主机地址解析映射到主机名称的过程我们称之为主机地址解析。这两个过程是相对应的。
在WinSock API 中,主机名称解析函数是gethostbyname()和WSAAsyncGetHostByName()。实现主机地址解析的函数是gethostbyaddr()和WSAAsyncGetHostByAddr()。
8.1.1 hostent结构
struct hostent { char FAR * h_name; /* official name of host */ char FAR * FAR * h_aliases; /* alias list */ short h_addrtype; /* host address type */ short h_length; /* length of address */ char FAR * FAR * h_addr_list;/* list of addresses */#define h_addr h_addr_list[0] /* address, for backward compat */};
h_name: 包括了公开的主机名称。h_aliases: 指向一个字符串指针数组(字符串以空NULL结尾)。每个字符串指向一个别名,别名是主机的一个备用名称,是公开主机名的同义词。在域名系统数据库中,每个别名均拥有一个规范名(CNAME)用来标识主机在DNS中的名称。当用户需要解析一个别名时,首先得到的是一个DNS中使用的规范名称,然后通过这个规范名称检索主机的地址。h_addrtype: 表示了h_addr_list域指向的地址类型。目前TCP/IP结构中只用两种值:AF_INET或者PF_INET。h_length: 表示域h_addr_list所指向的每个地址的字节长度。根据域h_addrtype所标识的地址类型值的不同,h_length的值有所不同。如TCP/IP(h_addrtype = AF_INET)中,h_length的值总为4.h_addr_list: 指向一个按照网络字节顺序的网络地址的指针数组(由于主机可能拥有多个网络接口,所以一些主机拥有多个网络地址)。这组指针的末尾有一个标识结束的空指针(NULL)。域h_length表示每个地址的长度。宏h_addr的定义是为了简化初始地址的访问过程(数组的第一个元素)h_addr_list[0]
8.1.2 主机名称解析
应用程序只有拥有主机地址才能与其进行通信。WinSock的监听、连接、发送和接收函数使用的都是网络地址,而不是主机名。然而,人们通常使用的都是主机名称,因此需要首先执行主机名称解析才能发起通信。
主机名称解析包含两个函数。两者的主要不同是操作方法的不同,但在缓存区的使用方面两者也有很大的不同。
gethostbyname():在主机名称解析完成前,gethostbyname()一致处在阻塞状态。WinSock将结果存储在共享的系统缓存中。
WSAAsyncGetHostByName(): 结果立即返回。当主机名称解析完成时,Winsock异步地通知应用程序。WinSock将结果存储在用用程序提供的缓存区中。
需要注意的是,我们不能把一个IP地址字符串,如”128.127.0.1”作为主机名输入函数,这将使得函数由于不能识别主机而返回错误信息WSAHOST_NOT_FOUND。
当应用程序提示用户输入一个目的主机是,应该允许用户输入一个主机地址或主机名。这就要求应用程序可以正确处理这两种情况。
- gethostbyname()
gethostbyname()使用主机名访问WinSock实际应用的一个主机数据库(例如主机表、域名系统、网络信息服务等),并返回完整的主机信息,其中包括公开主机名、所有已知的别名及接口地址。
struct hostent FAR *WSAAPI gethostbyname( const char FAR * name );
若解析成功,函数将返回一个指向hostent结构的指针,它指向存储结构的系统缓存,若解析失败,将返回一个空指针。操作失败的情况下,可以通过调用WSAGetLastError()函数对错误进行跟踪。最常见的错误值是WSAHOST_NOT_FOUND,它是发生在不能解析主机名的时候。用户应该及时备份系统缓存的内容,如果没有这么做,后面调用的非函数可能会覆盖前面函数的返回结果。
2.WSAAsyncGetHostByName()
HANDLE WSAAPI WSAAsyncGetHostByName( HWND hWnd, // window to rcv msg on completion u_int wMsg, // message to be rcvd on completion const char FAR * name, // ptr to name of host to be resolved char FAR * buf, // ptr to data area to rcv hostent data int buflen // size of data area buf above);
hWnd: 当主机名称解析完成后,打算接收异步通知消息的窗口的句柄。
wMsg:当主机名称解析操作完成后,WinSock发送给用户的消息值。
name: 一个以空(NULL)结尾的主机名字符串。
buf:一个指向缓存区地址的指针,WinSock可以从这个缓存区中复制解析成功的主机信息。
buflen:buf参数指向的缓存区大小。
WSAAsyncGetHostByName()函数总是在操作完成之前返回结果。解析操作在后台执行,解析完成后向应用程序发送异步通知消息。若操作失败,用户可以调用WSAGetLastError()函数来获取失败的原因。若操作成功,函数返回一个非0的异步查询句柄,用户可以通过这个句柄识别后续的异步消息响应。
注意:在主机名称解析过程完成时,buf所指向的存储区必须是可用的。所以在调用WSAAsyncGetHostByName()函数后,虚要确定已经将一个可用的持久性的缓存区分配给了用户。也就是说需要一个全局的缓存区或静态的缓存区,而不是在调用WSAAsyncGetHostByName()函数时动态创建的缓存区。
8.1.3 地址解析
struct hostent FAR * WSAAPI gethostbyaddr( const char FAR * addr, // ptr to address in network byte order int len, // length of address (4 if af == AF_INET) int type // type of address (AF_INET == TCP/IP));
addr: 带解析的主机地址。主机地址应该是按照网络字节顺序存储的
len:网络地址的字节长度。
type:in_addr中网络地址的类型。
2.WSAAsyncGetHostByAddr()
HANDLE WSAAPI WSAAsyncGetHostByAddr( HWND hWnd, // window to rcv msg on completion u_int wMsg, // mesage to be rcvd on completion const char FAR * addr, // ptr to address of host int len, // length of address int type, // type of address char FAR * buf, // ptr to data area to rcv hostent data int buflen // size of data area buf above);
hWnd:当主机地址解析操作完成后,要接收异步通知消息的窗口句柄。
wMsg:当主机地址解析操作完成后,WinSock发送给用户的消息的值。
addr:待解析的主机地址。
len:网络地址的字节长度。
type:in_addr中网络地址的类型。
buf:一个指向缓存区地址的指针,WinSock可以从这个缓存区中复制解析成功的主机信息。
buflen:buf参数指向的缓存区大小。
8.2 主机表、域名系统和网络信息服务
8.2.1 主机表
一个包含主机名和相应网络地址的文件成为主机表。
使用本地主机主机表的优点有以下几个:
1. 由于不存在网络的输入、输出操作,所以主机名称解析过程快。尤其在通过串行线连接或DNS服务器距离很远或网速慢、不可达等情况下,本地主机表的优点尤为突出。
2. 允许用户有自己的映射表。用户可以为主机添加一些域名服务器不知道的别名、条目等。
但是主机表也有以下几个缺点:
1. 一般的网络中不可能维持一个包含所有主机的列表。
2. 内容更新比较困难
3. 本地主机中的主机表内容与真实的网络地址之间存在差异。
8.2.2 域名系统
由于不可能每个主机都维护一个主机表,所以就有了取代这种静态主机表的一个动态分布式的数据库系统——域名系统。DNS的最大特点是各个服务器间共享主机的信息。DNS的更新是一个接一个的。当一台服务器不知道主机请求时,它将把请求发送给其他的服务器。
主机名的语法描述如下:
[host name.][subdomain.[subdomian.]…][domain][.]
一个完整的域名包含了各个部分及最后的点。若应用程序不提供一个完整的域名是,TCP/IP实施可以通过添加确实构建的方法完成主机名称解析。
若Winsock被配置为使用DNS进行主机名称解析,那么主机名称解析或地址解析函数的调用会产生一个DNS服务器查询请求。查询类型如下:
1. 带有完整主机名的”IP地址”(A)域名解析查询。
2. 带有IP地址字节逆转和in-addr.arpa顶级域的指针记录(PTR)地址解析请求。
3. 所有记录的查询请求(× or ANY)。
8.2.3 网络信息服务
Sun公司的网络信息服务提供与DNS相似的域名解析服务。其通常与DNS一起进行域名解析。确切地说,网络信息服务(Network Information Service,NIS)在一个网络内提供主机间的/etc/hosts文件的同步。
网络信息服务很少有WinSock应用程序使用。
8.3 本地主机信息
通过Windows Sockets应用程序接口(API)得不到本地主机的IP地址。因此应用程序只能通过两种方法找到本地主机的IP地址。但是,这两种方法都是间接的,不可靠的。
1. 首先调用gethostname(),然后调用gethostbyname()(或者调用WSAAsyncGetHostByName()函数)。
2. 连接好的socket可以调用getsockName()。
由于使用这两种方法都存在错误。所以通常将两者结合起来一起使用以求降低出错的可能性。
gethostname()将本地主机名复制到应用程序提供的缓存区中。
int WSAAPI gethostname( // 0 on success, or SOCKET_ERROR char FAR * name, // buffer to receive host name int namelen // length of name buffer );
name:WinSock将本地主机名复制到的目标缓存区
namelen:name缓存区的字节长度。
不同的实现方式有着不同的表现特征:
1. 函数执行成功并返回空字符串(NULL)
2. 报告出错并返回WSAHOST_NOT_FOUND错误
3. 返回一个特殊的主机名,gethostbyname()函数将这个主机名当成是本地的主机名。
即使应用程序得到了本地主机名,WinSock规范也不能保证将主机名称解析到本地IP地址。
8.4 网络地址与格式化
一个网络地址可以有两种格式:数字和字符串。一个IP地址是一个32为的无符号整数,如0x807F3201(按照网络字节顺序,即大端格式)。另一种标准字符串表达式,因特网点分表示法,如 128.127.50.1.
WinSock分别用两个函数实现数字形式的IP地址与字符串形式的IP地址见的相互转换:inet_ntoa()和inet_addr()。
8.4.1 in_addr结构
网络地址数据结构包含一个按照网络字节顺序存储的32位网络协议地址。
struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr;} S_un;#define s_addr S_un.S_addr /* can be used for most tcp & ip code */#define s_host S_un.S_un_b.s_b2 /* host on imp */#define s_net S_un.S_un_b.s_b1 /* network */#define s_imp S_un.S_un_w.s_w2 /* imp */#define s_impno S_un.S_un_b.s_b4 /* imp # */#define s_lh S_un.S_un_b.s_b3 /* logical host */};
用户可以通过下面的宏来访问具体的地址内同,从而将IP地址进行分解。
s_addr:按照网络字节顺序的32为完整IP地址值。多数使用in_addr结构的应用程序发现使用这个宏非常方便。
s_net:网络地址的第一个字节,它标识了IP地址的类型(例如A类:0~127,B类:128~191,C类:192~223,D类(多播):224——239,E类(预留):240~255)。
s_host、s_imp、s_impno,s_lh:这些都是不会被使用到的宏,属于Berkeley Sockets的遗留物。
通用地址
INADDR_ANY:标识任意的IP地址。在调用bind()函数请求网络系统分配默认接口地址前,应用程序通常调用这个宏来初始化sockaddr_in结构的sin_addr域。
INADDR_NONE:标识一个无效的IP地址。WinSock调用inet_addr()函数后,返回该值表示操作失败。
INADDR_BROADCAST: 标识了标准的IP受限广播地址”255.255.255.255”的32位值。应用程序通常需要使用这个宏来发送和接收标准的广播地址。
INADDR_LOOPBACK:标识了标准的IP回环地址”127.0.0.1”。
8.4.2 inet_addr()
inet_addr():将标准网络点分记法的字符串转换为网络自己顺序的数字型地址。
unsigned long WSAAPI inet_addr( const char FAR * cp // a char string in Internet "." format);
cp:点分记法的IP地址,由4个0~255之间的十进制数字组成,数字间用点分隔
这个函数的失败原因主要有两个:字符串不是一个有效的IP地址表示(格式错误或数值超出范围),或者是由于所指向的缓存区是虚假的。
如果用户填写的IP地址不完整,这个函数会智能地补全缺失内容。其方法如下:
如果用户提供IP地址形式为三段内容(a.b.c)那么将把最后一段的内容作为一个16位的值处理。例如,如果用户给出的地址是”128.127.6”,inet_ntoa()函数将把它转换成”128.127.0.6”;如果用户给出的地址是”128.127.12866”,那么inet_ntoa()函数将把它转换成”128.127.50.66”。三段标记便于定义B类地址xxx.net.host(xxx 是一个128~191之间的数值,表明是一个B类IP地址)。
如果用户提供了IP地址四段中的两段内容(a.b),那么它将把最后一段的内容作为一个24位的值传给地址最有段德部分。例如,它将”92.65”转换成”92.0.0.65”,将”92.9876”转换为”92.0.38.148”。WinSock的监听、连接、发送和接收函数使用的都是网络地址,而不是主机名。然而,人们通常使用的都是主机名称,因此需要首先执行主机名称解析才能发起通信。如果用户提供了IP地址四段中的一段内容,那么将直接存储这一段的内容,不进行任何字节的调整。例如,如果用户输入的内容为”65”,那么结果为”0.0.0.65”;如果用户输入的内容为”2155819555”,那么结果为”128.127.50.35”。
8.4.3 inet_ntoa()
inet_ntoa()讲一个32位的数字标记法网络地址转换为因特网标准点分记法的ASCII字符串
char FAR * WSAAPI inet_ntoa( struct in_addr in // Internet address stucture);
in:IP地址值,任何32位的值都可以。
这个函数基本上是不会失败的。它是一个检查返回值是否为空指针的好方法。
8.5 协议族与地址族
hostent结构的h_addrtype域与因特网socket结构的sockaddr_in中的sin_family域相对应。它们可以取值为:AF_INET或者PF_INET。
- 第八章 主机名称与主机地址
- 网络编程之获取主机名称与IP地址
- 网络地址与主机地址
- c#获取主机名称网卡MACIP地址
- 根据ip地址获取主机名称
- javascript 读取客户端MAC地址、IP地址、主机名称
- web页面获取客户端mac地址,IP地址,主机名称
- js获取IP地址 mac地址 主机名称
- 实现获取主机名称,IP地址的类 (java)
- DNS服务中取得主机名称和IP地址
- 获取局域网所有IP地址和主机名称
- Java网络编程 获取本地主机名称和地址
- 获取主机名称
- ubuntu修改主机名称
- ubuntu 修改主机名称
- 查找主机名称
- ubuntu修改主机名称
- 修改linux主机名称
- 开门人和关门人
- tomcat 启动异常排查
- 算法竞赛入门经典:第六章 数据结构基础 6.10黑白图像
- java内存管理:垃圾回收机制
- iOS请求网络数据的方式
- 第八章 主机名称与主机地址
- 模态,非模态对话框
- 超级文件分割《合并》机(分割大文件)
- hdu4109
- 高精度之快速幂
- Jetty vs. Tomcat
- 算法竞赛入门经典:第六章 数据结构基础 6.11迷宫
- CentOS下使用yum安装配置和使用svn
- 黑马程序员--Java基础学习(数组)第四天