IPv6 Winsock 应用程序 Dual-Stack 套接字Dual-Stack Sockets for IPv6 Winsock Applications

若要在 Windows XP Service Pack 1 (SP1) 和 Windows Server 2003 上同时支持 IPv4 和 IPv6,应用程序必须创建两个套接字,一个套接字用于 IPv4,另一个套接字用于 IPv6。In order to support both IPv4 and IPv6 on Windows XP with Service Pack 1 (SP1) and on Windows Server 2003, an application has to create two sockets, one socket for use with IPv4 and one socket for use with IPv6. 这两个套接字必须由应用程序单独处理。These two sockets must be handled separately by the application.

Windows Vista 和更高版本提供了创建单个 IPv6 套接字的功能,该套接字可以处理 IPv6 和 IPv4 通信。Windows Vista and later offer the ability to create a single IPv6 socket which can handle both IPv6 and IPv4 traffic. 例如,为 IPv6 创建 TCP 侦听套接字,并将其置于双堆栈模式,并绑定到端口5001。For example, a TCP listening socket for IPv6 is created, put into dual stack mode, and bound to port 5001. 此双堆栈套接字可接受连接到端口5001的 IPv6 TCP 客户端和连接到端口5001的 IPv4 TCP 客户端的连接。This dual-stack socket can accept connections from IPv6 TCP clients connecting to port 5001 and from IPv4 TCP clients connecting to port 5001. 此功能可以极大地简化应用程序设计,并减少在两个不同的套接字上发布操作所需的资源开销。This feature allows for greatly simplified application design and reduces the resource overhead required of posting operations on two separate sockets.

创建 Dual-Stack 套接字Creating a Dual-Stack Socket

默认情况下,在 Windows Vista 和更高版本上创建的 IPv6 套接字仅通过 IPv6 协议进行操作。By default, an IPv6 socket created on Windows Vista and later only operates over the IPv6 protocol. 为了使 IPv6 套接字成为双堆栈套接字,必须使用 IPv6 _ V6ONLY socket 选项调用 setsockopt函数,以便在套接字绑定到 IP 地址之前将此值设置为零。In order to make an IPv6 socket into a dual-stack socket, the setsockopt function must be called with the IPV6_V6ONLY socket option to set this value to zero before the socket is bound to an IP address. ipv6 _ V6ONLY 套接字选项设置为0时,为 AF _ INET6 地址族创建的套接字可用于向 IPV6 地址或 IPv4 映射地址发送数据包以及从 IPV6 地址或 IPv4 映射地址接收数据包。When the IPV6_V6ONLY socket option is set to zero, a socket created for the AF_INET6 address family can be used to send and receive packets to and from an IPv6 address or an IPv4 mapped address.

具有 Dual-Stack 套接字的 IP 地址IP Addresses with a Dual-Stack Socket

双堆栈套接字始终需要 IPv6 地址。Dual-stack sockets always require IPv6 addresses. 与 IPv4 地址进行交互的功能需要使用 IPv4 映射的 IPv6 地址格式。The ability to interact with an IPv4 address requires the use of the IPv4-mapped IPv6 address format. 所有 IPv4 地址必须以 IPv4 映射的 IPv6 地址格式表示,这使得仅支持 IPv6 的应用程序能够与 IPv4 节点通信。Any IPv4 addresses must be represented in the IPv4-mapped IPv6 address format which enables an IPv6 only application to communicate with an IPv4 node. IPv4 映射的 IPv6 地址格式允许 IPv4 节点的 IPv4 地址表示为 IPv6 地址。The IPv4-mapped IPv6 address format allows the IPv4 address of an IPv4 node to be represented as an IPv6 address. IPv4 地址编码为 IPv6 地址的低序位32位,高序位96位保存固定前缀0:0:0:0:0: FFFF。The IPv4 address is encoded into the low-order 32 bits of the IPv6 address, and the high-order 96 bits hold the fixed prefix 0:0:0:0:0:FFFF. 在 RFC 4291 中指定了 IPv4 映射的 IPv6 地址格式。The IPv4-mapped IPv6 address format is specified in RFC 4291. 有关详细信息,请参阅 www.ietf.org/rfc/rfc4291.txtFor more information, see www.ietf.org/rfc/rfc4291.txt. _ Mstcpip 中的 IN6ADDR SETV4MAPPED 宏可用于将 ipv4 地址转换为所需的 Ipv4 映射的 IPv6 地址格式。The IN6ADDR_SETV4MAPPED macro in Mstcpip.h can be used to convert an IPv4 address to the required IPv4-mapped IPv6 address format.

如果基础协议实际上是 IPv4,则 IPv4 地址将映射为 IPv4 映射的 IPv6 地址格式。If the underlying protocol is actually IPv4, then the IPv4 address is mapped into an IPv4-mapped IPv6 address format. 这是 SOCKADDR 结构中的 "家族" 字段,它指示 AF _ INET6,但 IPv4 映射的 IPv6 地址在 IPv6 地址结构中进行编码。That is the, family field in the SOCKADDR structure indicates AF_INET6, but an IPv4-mapped IPv6 address is encoded in the IPv6 address structure. 对于处于监听模式的双堆栈套接字,这意味着任何已接受的 IPv4 连接将返回 IPv4 映射的 IPv6 地址。For a dual-stack socket in listening mode, this means that any accepted IPv4 connections will return an IPv4-mapped IPv6 address. 对于连接到 IPv4 目标的双堆栈套接字,传递到连接的 SOCKADDR 结构必须是 IPv4 映射的 IPv6 地址。For a dual-stack socket that is connecting to an IPv4 destination, the SOCKADDR structure passed to connect must be an IPv4-mapped IPv6 address. 应用程序必须小心地处理这些 IPv4 映射的 IPv6 地址,只需将它们与双堆栈套接字一起使用。Applications must take care to handle these IPv4-mapped IPv6 addresses appropriately and only use them with dual stack sockets. 如果 IP 地址要传递到常规 IPv4 套接字,则该地址必须是 IPv4 映射的 IPv6 地址。If an IP address is to be passed to a regular IPv4 socket, the address must be a regular IPv4 address not a IPv4-mapped IPv6 address.

使用 Dual-Stack 套接字时可能存在的问题Potential Issues using a Dual-Stack Socket

应用程序的潜在缺陷是在双堆栈套接字上获取 IPv4 映射的 IPv6 地址,然后尝试在不同的 IPv6 套接字上使用返回的 IP 地址。A potential pitfall for applications is getting an IPv4-mapped IPv6 address on a dual-stack socket and then trying to use the returned IP address on a different IPv6 only socket. 例如, getsocknamegetpeername 函数在双堆栈套接字上使用时,可以返回 IPv4 映射的 IPv6 地址。For example, the getsockname or getpeername functions can return an IPv4-mapped IPv6 address when used on a dual-stack socket. 如果随后在未设置为双堆栈的另一个套接字上使用返回的 IPv4 映射的 IPv6 地址 (仅限 IPv6 的套接字(这是) 创建套接字时的默认行为),则在使用 IPv4 映射的 IPv6 地址的情况下,仅使用此 IPv6 套接字会失败。If the returned IPv4-mapped IPv6 address is then subsequently used on a different socket that was not set to dual-stack (an IPv6 only socket which is the default behavior when a socket is created), any use of this IPv6 only socket with an IPv4-mapped IPv6 address will fail. IPv4 映射的 IPv6 地址格式仅可用于双堆栈套接字。The IPv4-mapped IPv6 address format can only be used on a dual-stack socket.

在双堆栈数据报套接字上,如果应用程序需要 LPFN_WSARECVMSG (WSARECVMSG) 函数以 WSAMSG 结构返回通过 IPv4 接收的数据报的数据包信息,则必须在套接字上将 IP _ PKTINFO socket 选项设置为 true。On a dual-stack datagram socket, if an application requires the LPFN_WSARECVMSG (WSARecvMsg) function to return packet information in a WSAMSG structure for datagrams received over IPv4, then IP_PKTINFO socket option must be set to true on the socket. 如果套接字上只有 IPV6 _ PKTINFO 选项设置为 true,则将为通过 IPV6 接收的数据报提供数据包信息,但可能不会为通过 IPv4 接收的数据报提供数据包信息。If only the IPV6_PKTINFO option is set to true on the socket, packet information will be provided for datagrams received over IPv6 but may not be provided for datagrams received over IPv4.

如果某个应用程序尝试在双堆栈数据报套接字上设置 IP _ PKTINFO 套接字选项,并且在系统上禁用了 IPv4,则 setsockopt 函数将失败, WSAGetLastError 将返回错误,并返回 WSAEINVALIf an application tries to set the IP_PKTINFO socket option on a dual-stack datagram socket and IPv4 is disabled on the system, then the setsockopt function will fail and WSAGetLastError will return with an error of WSAEINVAL. 由于其他错误, setsockopt 函数也会返回此错误。This same error is also returned by the setsockopt function as a result of other errors. 如果应用程序尝试 _ 在双堆栈套接字上设置 IPPROTO IP 级别套接字选项,并且该选项在 WSAEINVAL上失败,则应用程序应确定本地计算机上是否禁用了 IPv4。If an application tries to set an IPPROTO_IP level socket option on a dual-stack socket and it fails with WSAEINVAL, then the application should determine if IPv4 is disabled on the local computer. 可用于检测是否启用或禁用 IPv4 的一种方法是调用 套接字 函数,并将 af 参数设置为 af INET, _ 以尝试创建 ipv4 套接字。One method that can be used to detect if IPv4 is enabled or disabled is to call the socket function with the af parameter set to AF_INET to try and create an IPv4 socket. 如果 套接字 函数失败并且 WSAGetLastError 返回 WSAEAFNOSUPPORT错误,则意味着不启用 IPv4。If the socket function fails and WSAGetLastError returns an error of WSAEAFNOSUPPORT, then it means IPv4 is not enabled. 在这种情况下 , _ 应用程序可以忽略尝试设置 IP PKTINFO 套接字选项时的 setsockopt 函数失败。In this case, a setsockopt function failure when attempting to set the IP_PKTINFO socket option can be ignored by the application. 否则,尝试设置 IP _ PKTINFO socket 选项时,应将其视为意外错误。Otherwise a failure when attempting to set the IP_PKTINFO socket option should be treated as an unexpected error.

当使用 WSASendMsg 函数发送数据报并且应用程序要指定要使用的特定本地 IP 源地址时,对于双堆栈套接字,处理此情况的方法取决于目标 IP 地址。For a dual-stack socket when sending datagrams with the WSASendMsg function and an application wants to specify a specific local IP source address to be used, the method to handle this depends on the destination IP address. 当发送到 IPv4 目标地址或 IPv4 映射的 IPv6 目标地址时,通过 lpMsg 参数指向的 WSAMSG结构中传递的控件数据对象之一应包含 _ pktinfo 结构中的,其中包含用于发送的本地 IPv4 源地址。When sending to an IPv4 destination address or an IPv4-mapped IPv6 destination address, one of the control data objects passed in the WSAMSG structure pointed to by the lpMsg parameter should contain an in_pktinfo structure containing the local IPv4 source address to use for sending. 如果发送到的 IPv6 目标地址不是 IPv4 映射的 IPv6 地址,则在 lpMsg 参数指向的 WSAMSG 结构中传递的控件数据对象之一应包含 in6 _ pktinfo结构,其中包含用于发送的本地 IPv6 源地址。When sending to an IPv6 destination address that is not a an IPv4-mapped IPv6 address, one of the control data objects passed in the WSAMSG structure pointed to by the lpMsg parameter should contain an in6_pktinfo structure containing the local IPv6 source address to use for sending.

适用于 Windows 套接字应用程序的 IPv6 指南IPv6 Guide for Windows Sockets Applications

更改 IPv6 Winsock Appications 的数据结构Changing Data Structures for IPv6 Winsock Appications

IPv6 Winsock 应用程序的函数调用Function Calls for IPv6 Winsock Applications

使用硬编码的 IPv4 地址Use of Hardcoded IPv4 Addresses

IPv6 Winsock 应用程序的用户界面问题User Interface Issues for IPv6 Winsock Applications

IPv6 Winsock 应用程序的基础协议Underlying Protocols for IPv6 Winsock Applications

getpeernamegetpeername

getsocknamegetsockname

在 _ pktinfo 中in_pktinfo

in6 _ pktinfoin6_pktinfo

IP _ PKTINFOIP_PKTINFO

IPV6 _ PKTINFOIPV6_PKTINFO

setsockoptsetsockopt

LPFN_WSARECVMSG (WSARecvMsg)LPFN_WSARECVMSG (WSARecvMsg)

WSASendMsgWSASendMsg