IPv6名称到地址的转换函数getaddrinfo()详解

2004-12-12 (修改)
IPv4
中使用 gethostbyname() 函数完成主机名到地址解析,但是该 API 不允许调用者指定所需地址类型的任何信息,返回的结构只包含了用于存储 IPv4 地址的空间。为了解决该问题, IPv6 中引入了 getaddrinfo() 的新 API ,它是协议无关的,既可用于 IPv4 也可用于 IPv6 。调用该函数会获得一个 addrinfo 结构的列表,调用的返回值是 addrinfo 的结构(列表)指针。
       本文结合在 WinowsXP Windows2003 Server 上使用该函数的经验,对 getaddrinfo 函数和 addrinfo 数据结构进行介绍,并对其参数的设置加以讨论,主要包括 nodename servname 的取值对返回值的影响, hints 成员变量的设置对返回值的影响等。
可能有不完全或不准确的地方,欢迎大家讨论并指出。
1.getaddrinfo函数原型
函数
参数说明
int getaddrinfo(
const char* nodename
const char* servname,
const struct addrinfo* hints,//
struct addrinfo** res
);
nodename: 节点名可以是主机名,也可以是数字地址。( IPV4 10 进点分,或是 IPV6 16 进制)
servname: 包含十进制数的端口号或服务名如( ftp,http
hints: 是一个空指针或指向一个 addrinfo 结构的指针,由调用者填写关于它所想返回的信息类型的线索。
res: 存放返回 addrinfo 结构链表的指针
Getaddrinfo 提供独立于协议的名称解析。
函数的前两个参数分别是节点名和服务名。节点名可以是主机名,也可以是地址串 (IPv4 的点分十进制数表示或 IPv6 的十六进制数字串 ) 。服务名可以是十进制的端口号,也可以是已定义的服务名称,如 ftp http 等。注意:其中节点名和服务名都是可选项,即节点名或服务名可以为 NULL ,此时调用的结果将取缺省设置,后面将详细讨论。
函数的第三个参数 hints addrinfo 结构的指针,由调用者填写关于它所想返回的信息类型的线索。函数的返回值是一个指向 addrinfo 结构的链表指针 res
2.addrinfo结构
结构
固定的参数
typedef struct addrinfo { 
int ai_flags; 
int ai_family; 
int ai_socktype; 
int ai_protocol; 
size_t ai_addrlen; 
char* ai_canonname; 
struct sockaddr* ai_addr; 
struct addrinfo* ai_next;
}
ai_addrlen must be zero or a null pointer
ai_canonname must be zero or a null pointer
ai_addr must be zero or a null pointer
ai_next must be zero or a null pointer
可以改动的参数
ai_flags:AI_PASSIVE,AI_CANONNAME,AI_NUMERICHOST
ai_family: AF_INET,AF_INET6
ai_socktype: SOCK_STREAM,SOCK_DGRAM
ai_protocol: IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc.
3 参数说明
getaddrinfo 函数之前通常需要对以下 6 个参数进行以下设置: nodename servname hints ai_flags ai_family ai_socktype ai_protocol
6 项参数中,对函数影响最大的是 nodename sername hints.ai_flag
ai_family 只是有地址为 v4 地址或 v6 地址的区别。而 ai_protocol 一般是为 0 不作改动。
其中 ai_flags ai_family ai_socktype 说明如下:
参数
取值
说明
ai_family
AF_INET
2
IPv4
AF_INET6
23
IPv6
AF_UNSPEC
0
协议无关
ai_protocol
IPPROTO_IP
0
IP 协议
IPPROTO_IPV4
4
IPv4
IPPROTO_IPV6
41
IPv6
IPPROTO_UDP
17
UDP
IPPROTO_TCP
6
TCP
ai_socktype
SOCK_STREAM
1
SOCK_DGRAM
2
数据报
ai_flags
AI_PASSIVE
1
被动的,用于 bind ,通常用于 server socket
AI_CANONNAME
2
 
AI_NUMERICHOST
4
地址为数字串
 
对于 ai_flags 值的说明:
AI_NUMERICHOST
AI_CANONNAME
AI_PASSIVE
0/1
0/1
0/1
如上表所示, ai_flagsde 值范围为 0~7 ,取决于程序如何设置 3 个标志位,比如设置 ai_flags  “AI_PASSIVE|AI_CANONNAME” ai_flags 值就为 3 。三个参数的含义分别为:
(1)AI_PASSIVE 当此标志置位时,表示调用者将在 bind() 函数调用中使用返回的地址结构。当此标志不置位时,表示将在 connect() 函数调用中使用。
当节点名位 NULL ,且此标志置位,则返回的地址将是通配地址。
如果节点名 NULL ,且此标志不置位,则返回的地址将是回环地址。
(2)AI_CANNONAME 当此标志置位时,在函数所返回的第一个 addrinfo 结构中的 ai_cannoname 成员中,应该包含一个以空字符结尾的字符串,字符串的内容是节点名的正规名。
(3)AI_NUMERICHOST 当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串。
4.实际使用的几种常用设置
一般情况下, client/server 编程中, server 端调用 bind (如果面向连接的还需要 listen ), client 则不用掉 bind 函数,解析地址后直接 connect (面向连接)或直接发送数据(无连接)。因此,比较常见的情况有
(1)       通常服务器端在调用 getaddrinfo 之前, ai_flags 设置 AI_PASSIVE ,用于 bind ;主机名 nodename 通常会设置为 NULL ,返回通配地址 [::]
(2)       客户端调用 getaddrinfo 时, ai_flags 一般不设置 AI_PASSIVE ,但是主机名 nodename 和服务名 servname (更愿意称之为端口)则应该不为空。
(3)       当然,即使不设置 AI_PASSIVE ,取出的地址也并非不可以被 bind ,很多程序中 ai_flags 直接设置为 0 ,即 3 个标志位都不设置,这种情况下只要 hostname servname 设置的没有问题就可以正确 bind
 
上述情况只是简单的 client/server 中的使用,但实际在使用 getaddrinfo 和参考国外开源代码的时候,曾遇到一些将 servname (即端口)设为 NULL 的情况
( 当然,此时 nodename 必不为 NULL ,否则调用 getaddrinfo 会报错 ) 。以下分情况进行了测试:
(1)       如果 nodename 是字符串型的 IPv6 地址, bind 的时候会分配临时端口;
(2)       如果 nodename 是本机名, servname NULL ,则根据操作系统的不同略有不同,本文仅在 WinXP Win2003 上作了测试。
a)         WinXP 系统( SP2 )返回 loopback 地址 [::1] (在XP下,即使servname不为空,返回的地址仍然是[::1],即XP下只要nodename是本机名,返回的地址就是[::1],无法返回别的 地址,不知道是不是XP实现时的问题,因为[::1]只能用作本机测试,绑定在其上的socket是无法被别的机器寻址的)
b)        Win2003 则将本机的所有 IPv6 地址列表加以返回。因为通常一台 IPv6 主机都有可能不止一个 IPv6 地址,比如 fe80::1 (本机 loopback 地址)、 fe80::*** Link-Local 地址、 3ffe:*** 的全局地址等等。这种情况下调用 getaddrinfo 会将这些地址全部返回,调用者应该注意如何使用这些地址。另外要注意的是,对于 fe80:: 的地址在绑定的时候必须标明接口地址,即使用 fe80::20d:60ff:fe78:51c2%4 fe80::1%1 这样的地址格式,通过 getaddrinfo 直接取出 fe80 地址好像无法直接 bind
 
5.几句废话
Windows 环境调试 IPv6 的程序个人感觉还是使用 WinXP SP2 )和 Win2003 基本上没有太大的区别,使用 Win2003 更规范一些。
VC 编写和调试 IPv6 的程序一定要安装 Windows 较新的 SDK ,我安装的是 MS_Platform_SDK_Feb_2003 ,否则库函数和头文件可能都会有问题。
 
 
[ 参考 ]
[1]MSDN Library – January 2 004
ms-help://MS.MSDNQTR.2004JAN.1033/winsock/winsock/getaddrinfo_2.htm
ms-help://MS.MSDNQTR.2004JAN.1033/winsock/winsock/addrinfo_2.htm
[2] 《理解IPv6》("Understanding IPv6”),清华大学出版社
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值