兼容地址
最后一种单播地址是兼容地址,用来支持从IP4 到IPv6 的转。
Windows 支持4 种兼容地址:
- ISATAP(Intrasite Automatic Tunnel Addressing Protocol,现场自动隧道寻址协议)地址
- 6到4地址
- 6跨4地址
- IPv4兼容地址。
ISATAP
ISATAP 地址可以由何 IPv6 单播地址(如链接一地地址、站点一本地地址及全球地址等)派生而得,通常况下,ISATAP地址由链接一本地地址派生而得。这种地址也包括嵌入式IPv4 地址,例如,ISATAP 地址 fe80::5ee:172.17.72
是一个链接一本地地址,它含了主机的IPv4 地址(172.17.7.2)当数据从这个接口送出时Pv6 数据包被封到一个IPv4报头中IPv4 目的地址从嵌入到IPV6 ISATAP 目标地址的4 地址中获取。4 地址必须是球可访问的,以便两个端点能够通过自动隧道进行通信。目前, ISATAP地址是·项TETF(Internet Engineering Task Force.Intemnet 工程任务组) 草案
6到4地址
第 2种兼容地址称为“6 到 4”, RFC3056 中所叙述。6 4 地址使用全球前缴2002:WWXX:YYZZ::/48,具中 WWXX:YYZZ 是wxy( 种公IPV4 地址)的十六进制一冒号小法。6到4地址允许 IPv6/1Pv4 主机之间通过IPV4 路由结构进行通信
WindowsXP 支持6到4服务。这项服务不仅允许机和使用6到4中继路由器的IP6 网络中的主机通信,还允许主机和同一站点的6到4 主机、连接到Intenet的6到4主机以及跨越 IP4 网络的其他站点的上机通信。在 Windows XP 中6到4服务被配置为自功运行,如某个接口分配有公共IPv4地址,则系统将创建一个6到 4隧道接口(接索引为 3),并把6到4地址分配给该隧道接口。
6跨4地址
第3 种兼容地址是“6跨4”,这是一种使用 1Py4 多播的道技术。它使得IPv4 和 IPV6节点可以在IPv4 下层结构之上使用 IP6 进行通。这种技术在 RFC2529 中有所叙述
IPv4兼容地址
最后一种兼容地址是 IPv4 兼容地址。这种地址表现形式为 0:0:0:0:0:0:wx.y.z(或::wxy.z),其中w.x.y.z 是公共 IPv4 地址的点分进制表示。当应用程序使用 IP4 兼容地作为目的地址时,IPv6的通信量将被自动封装到IPv4 报头中,并通过 IPV4 网络送到目的地。
3.2.1.2 任播
任播是标识多接口的地址。使用这些地址的目的,足将指向一个任播地址的数据包路由到最近的分配有该地址的接口。当网络中有在几个节点提供某种特定的服务时,使用任播地址比较有利。每台计算机都可以分配同一个任播地址,有意联系这种服务的客户机将被路由到近的提供服务的成员处。因为这种通信是一个对多个之中的一个,而不是-·个对多个,所以它和多播不同。不过,山前任播地址仅分配下路由器。
3.2.1.3多播
[Pv6 中的多播和 IPV4 中的类似。只要进程在某个特定接口加入多播组,就可收到发往该多播地址的数据。IPv6多播地址以1111 1111(FF)作为开始部分。IPv6 多播和IP6多播地址在第9 章中详细叙述。
3.2.2 IPv6管理协议
IPv6 只需要一个助手协议:
- ICMPv6(Internet Control Message Protocol for iPv6,IP6 Internet 控制信息协议)。
RFC2463 中有对这个协议的定义。ICMP6 提供和ICMP 同种类型的服务,如:目标地无法访问、回应及回应答复,但它还提供 MLD(Multicast Listener Discovery,多播监听者搜寻)机制和ND(Neighbor Discovery,近邻发现)机制。在ICMPV6 中,MLD代替了IGMP,ND代替了ARP。
3.2.3 Winsock 中的iPv6 寻址
Winsock 应用科序中指定IPv6 地址时使用下述结构:
struct sockaddr_in6 { short sin6_family; u_short sin6_port; u_long sin6_flowinfo; struct in6 addr sin6_addr; u_long sin6_scope_id; }
第1个字段仅标识了地址族,该地址族为 AF_INET6,
第2个字段是端口号。这个结构中的所有字段都必须按照网络学节顺序排列。应注意到,因为端口号是封装协议的一个属性,所以 IPV4 部分中讨论的所有有关端口号的知识同样适用厂IPV6,如TCP 和UDP 在IP6 中两者都可用。
第3个字段 sin6_flowinfo 用于为连接标记通信量,但未在微软IPV6 堆 中使用。
第4个字段是一个包含了进制IPv6地址的 16字结后一个段 sin6_scope_id 指地址所在的接口索引(或范围ID)。应记住,对于链接一本地地址,必须指定目的地所在的本地范围 ID,sin6_scope_id 就用于这个目的站点——本地地址可以引用地址号码作为范围ID。全球地址不包含范围 ID。
最后应该注意的一个问题是,SOCKADDR_IN6 结构的长度为 28 字节,而 SOCKADDR 结构和SOCKADDR_IN 结构的长度仅为16 字节。
3.3 地址及名称解析
本节将讲述怎样分配两种 IP 的文字串地址,以及将两种 IP 的名称解析为地址专用结构。
先讲述新的名称解析APl;
getaddrino 和 getnameinfo
,这两个API代替了IPv4 与用例程。
然后讲述用于文字地址和套接字地址结构之间转换的常规 Winsock API,即 WSAAddressToString 和WSAStringToAddress。注意,这些函数仅执行地址转换和分配,不执行名称解析。
接着将叙述传统IPv4 专用例程。其中包括传统 API的说明,以应付有必要保留原有代似的场合不过任何新的工程项都应该使用新的API 函数,使用新的函数后,编写个在IPv4和IPv6上都能够无缝运行的应用程序就比较容易了,这将是本章下一节的主题。
最后应注意到,本章叙述的所有名称解析函数仅仪解析名称,不能将名称注册为·个地址。这项功能出第8章中讨论的 Winsock RNR(Registration and Name Resolution,注册及名称解析)API来完成
3.3.1 名称解析例程
有几个随 IPv6·起引进的新的名称解析函数能够处理 IPy4 和 IPV6 地址。原有的函数如gethosbyname 机 inet addr 只能处理 IPV4 地址,代它们的雨数名为 getnameinfo 和 getaddrinfo.
这两个新的名称解析函数 WS2TCPIP.H 中定义,同时要注意到,尽管这些函数是 Windows XP中的新雨数,但它们也能在所有支持 Winsock 2 的台运行,这只要在包含头文件 WS2TCPIPH前,包含头文竹 WSPTAPLH 即可,编译过的二进制文件则可以在所有文持 Winsock 2 的台上运行刻 Windows 95、Windows 98、Windows MeWindows NT 4.0 及 Windows 2000.
getaddrinfo 雨散提供独立下协议的名称解析。
函数原型为:
int getaddrinio ( const char FAR *nodename. Const char FAR *servname, const struct addrinfo FAR *hintsr struct addrinfo SAR *FAR *reg )
参数 nodename 指定以空字符结束的主机名和文字地址,servname 参数是个包含口号或服务名(如 他 或 telnet)的以空字符结束的学符串。
第3个参数数 hints 是一个结,它能传递一个或多个选项,这些选项将影响到名称解析的执行方式。城后,参数 res 返回 addrlNF 结构的 个链表,该结构包含了由字符申名称解析而的地址。如果操作成功,则返回 0:否则返回 Winsock 错误信息。
addrINFO 结构的定义为:
struct addrinfo { int ai_flags; int ai_familyi; int ai_socktype; int ai_protocol; size_t ai_addrlen; chal ai_canonname; struct sockaddr *ai_addr; struct addrinfo *ai_next; }
当要把 hints 结构传递到API 时,结构应预先置零,且结构的前4 个字段应相关联
- ai_flags 字段长示下述3个值的 :APASSIVE、ALCANONNAME或AINUMERICHOST。Al PASSIVE 表nodename 是一个计算机名(如 wwwmicrosofcom)AI_NUMERICHOST 示 nodename 是一个文字字符地址(如“10.10.10.1”)、稍后将讨论AI_PASSIVE。
- ai_family 子段表示AFINET、AF INET6或 AF UNSPEC,如果想析到个具体地,请键入 AF_INET AF INET6。则,如果给定 AF UNSPFC,则返回地址可能是 IPv4,也可能是 1Pv6,或者两个都返回。
- ai_socktype 字段指定要求的套接字类型如SOCKDGRAM或SOCK STREAM当servname包含服务名称时,这个字段就会被使用。也就是说,根据使用的是 UDP,还是 TCP,有些服务具有不同的端4号。
- ai_protocol字段指定要求的协议,如 IPPROTO TCP。跟上面一样当 servname 包含服务名称时,这个字段就有用。
如果没有 hints 结构传递给 getaddrinfo,函数将根据零 hints 结构执行,这时 ai family 取为AF UNSPEC.
如果函数解析名称成功,则解析后的地址会通过 res 返回。如果名称被解析为多个地址,则返回结果为一个由 ai.next 学段形成的链表。每个由名称解析而来的地址在 ai addr 中表示,其长度为ai addrlen 中给出的接字地址结构的长度。可以将这两个字段直接传递给 bind、connect、sendto等函数。
下面这一段代码示例展示了如何解析一个带有端口号的主机名,其中,解析操作是在与服务器建立一个TCP 连接之前进行的。
SOCKET s; struct addrinfo hintsr,*result; int rc; memset(&hints,Osizeofihintsj); hints.ai_lags = AI_CANONNAME; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; rc = getaddrinfo(”foobar",”50017,&hints,&result); if (rc != 0){ //无法解析名称 } s = socket(result->ai_family;result->ai_socktype,result->ai_protocol); if(s == INVALID_SOCKET){ //套接字 API 失败 } rc = connect(s,result->ai addr,result->ai addrlen); if (IC == SOCKET ERROR) //连接 API失败 } freeaddrinfo(result);
在这个示例中,应用程序试图解析主机名“foobar”,并希望在5001号端口与某项服务建立一个TCP 连接。您还会注意到,代码并不在乎名称被解析为 IPv4 地址,还是 IPv6 地址。可能“foobar两种地址都注册了,在这种情况下,result 将包含由 ai next 字段链的额外的 addriNFO 结构。如果应用程序希望“foobar”仅注册了IPv4 地址,则应将 hintsai family 设为AF INET。最后应注意,过 res 返同的信息是动态分配的,–用程序使用完这些信息之后,便需要调用 fecaddrinfo APl释放这些信息所占用的空间。
应用程序实施的另一个常见动作,将一个文字字符串地址(如“172.17.7.1”或“fe80.:1234”)分配到适当类型的套接字地址结构中。getaddrinfo函数在 hints 结构中设置AI NUMERICHOST 标志从而做到这“点。下面的代码展示了这一做法:
struct addrinfo hints,*result; int rc; memset(shints,0,sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; hints.ai_family = AI_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protoco1 = IPPROTO_TCP; rc =getaddrinfo("172.17,7.1",“5001",&hints,&result); if (rc !=0) { //文字字符串地;无效 } //使用 result freeaddrinfo(result)
文字学符串地址“172.17.7.1”将被转换为必要的接字地址结构,并通过 result 返回。因为传递了AF UNSPEC,API将确定所需的正确套接宁地址结构(SOCKADDR_IN 或 SOCKADDR_IN6),并将地址作机应转换,如前所述,转换后生成的套接字地址结构的端口字段将被初始化为 5001。
注意,如果没有将任何标志作为 hints 结构的·部分进行传递,那么在解析文宁字符串地址之后被返回的含有转换后地址的结构 addrinfo 将设置AI NUMERICHOST标志。同样,如果解析了主机名而没有传递任何 hints 结构,所返回的结构addrinfo 将包AI CANONNAME标志。
getaddrinfo 可以使用的最后一个标志是 AL PASSIVE,该标志用于获取能够传递给 bind 函数的地址。对F IPv4 而言,这个地址可能是 INADDR ANY(0.0.0.0),而对下 IPv6 而言则可能是IN6ADDR ANY(: )。为获取绑定地址,hints 结构应该指明要为哪个地址族获取该无源地址(通过ai family),nodename 应设为 NULL,servname 应设为非 NULL–指明应用程序要绑定到哪个端号(可以是0)。如果AF_UNSPEC 被传递到 hints 结构中,则两个addrINFO 结构将被返回,一个带有IPv4绑定地址,另一个带有 IPv6 绑定地址。
在使用 getaddrinfo 解析了主机名之后,AI_PASSIVE 标志就可以派上用场了。一解析后的地址被返回,就可以在另一次调用 getaddrinfo 时使用初始结中的 ai family(地址族),以便获取该地址放合适的绑定地址。这让应用程序避免了接触内部变接字地址结构的字段,也排除了使用两个独立的代码路径(即根据地址将解析到哪个地址来绑定套接字的两个独立路径)的必要
另 个新的名称解析 API是 gelnameinlo,其功能和 getaddrinfo 函数相反。该函数接受已经初始化的套接字结构,并返回与地址及端口信息对应的土机和服务名。函数原型为:
int getnameinfo( const struct sockdddr FAR *sd, socklen t salen, chdr FAR *hostr, DNORD hostlen, char EAR *serv, DWORD servlen, int flags )
其中各个参数的含义是较为明显的。参数 a 是套接地址结构,名称信息将从这个参数获取而参数 salen 则是该地址结构的大小。参数 ost 是接收主机名称的字符缓冲区,默认状态下将返回FQDN(fully qualified domain name,完全合格的城名)参数 hostlen 表示机缓冲区的大小。参数 serv是接收服务(或端口)信息的字符缓冲区,而参数 scrvlen 则表示该缓冲区的长度。最后,ags 参数指明将如何解析套接字地址。
flags 可能的取值如下,
- NINOFQDN:表明仅返RDN(relative distinguishedname,相对特异名)。例如,设置这个标志时,名为“mist.microsoft.com”的卡机将只返回“mist”
- NT_NUMERICHOST:表将返回用字符串表示的地址,而不返回主机名。
- NI_NAMEREOD: 表明如果地址不能被解析为 FODN,则返回错误信息NI
- NUMERICSERV: 表明将端口信息作为个字符串返回,而不会将口信息解析为一个已知的服务名(如“ftp”)。注意,如果在提供 scrv 缓冲区时缺少这个标志,且11号不能被解析为某种已知服务,则 genameinfo 将失败,出错信息为 WSANO DATA(11004)
- NI_DGRAM: 用来将数据报服务从流服务中区分开来。对于少数几个为 UDP TCP 定义了不同端门号的服务来说,这种区分是很有必要的。
在补充材料中有一个名为 RESOLVERCPP
的文件,该文件县有执行名称解析的功能。主机名或地址随同服务或端口信息一起被传递给应用程序,并通过 gctaddrinfo 雨数进行解析。然后,针对每个返回的已解析地址,调用函数 getnameinfo,以获得计算机名,或获取学符串文字地址。