适用于 IPv6 Winsock 应用程序的Dual-Stack套接字

为了在具有 Service Pack 1 的 Windows XP (SP1) 和 Windows Server 2003 上同时支持 IPv4 和 IPv6,应用程序必须创建两个套接字,一个套接字用于 IPv4,另一个套接字用于 IPv6。 应用程序必须单独处理这两个套接字。

Windows Vista 和更高版本提供创建单个 IPv6 套接字的功能,该套接字可以处理 IPv6 和 IPv4 流量。 例如,创建 IPv6 的 TCP 侦听套接字,将其置于双堆栈模式,并绑定到端口 5001。 此双堆栈套接字可以接受从连接到端口 5001 的 IPv6 TCP 客户端和从连接到端口 5001 的 IPv4 TCP 客户端的连接。 此功能可大大简化应用程序设计,并减少在两个单独的套接字上发布操作所需的资源开销。

创建Dual-Stack套接字

默认情况下,在 Windows Vista 及更高版本上创建的 IPv6 套接字仅通过 IPv6 协议运行。 若要将 IPv6 套接字转换为双堆栈套接字,必须使用 IPV6_V6ONLY 套接字选项调用 setockopt 函数,以便在将套接字绑定到 IP 地址之前将此值设置为零。 当 IPV6_V6ONLY 套接字选项设置为零时,可以使用为 AF_INET6 地址系列创建的套接字向 IPv6 地址或 IPv4 映射地址发送和接收数据包。

具有Dual-Stack套接字的 IP 地址

双堆栈套接字始终需要 IPv6 地址。 若要与 IPv4 地址交互,需要使用 IPv4 映射的 IPv6 地址格式。 任何 IPv4 地址都必须以 IPv4 映射的 IPv6 地址格式表示,这允许仅 IPv6 应用程序与 IPv4 节点通信。 IPv4 映射的 IPv6 地址格式允许将 IPv4 节点的 IPv4 地址表示为 IPv6 地址。 IPv4 地址编码为 IPv6 地址的低序 32 位,高序 96 位包含固定前缀 0:0:0:0:0:FFFF。 RFC 4291 中指定了 IPv4 映射的 IPv6 地址格式。 有关详细信息,请参阅 www.ietf.org/rfc/rfc4291.txtMstcpip.h 中的 IN6ADDR_SETV4MAPPED 宏可用于将 IPv4 地址转换为所需的 IPv4 映射 IPv6 地址格式。

如果基础协议实际上是 IPv4,则 IPv4 地址将映射到 IPv4 映射的 IPv6 地址格式。 即 SOCKADDR 结构中的系列字段指示AF_INET6,但 IPv4 映射的 IPv6 地址在 IPv6 地址结构中编码。 对于处于侦听模式的双堆栈套接字,这意味着任何接受的 IPv4 连接都将返回 IPv4 映射的 IPv6 地址。 对于连接到 IPv4 目标的双堆栈套接字,传递用于连接的 SOCKADDR 结构必须是 IPv4 映射的 IPv6 地址。 应用程序必须谨慎处理这些 IPv4 映射的 IPv6 地址,并且仅将它们与双堆栈套接字一起使用。 如果要将 IP 地址传递给常规 IPv4 套接字,该地址必须是常规 IPv4 地址,而不是 IPv4 映射的 IPv6 地址。

使用 Dual-Stack 套接字的潜在问题

应用程序的一个潜在缺陷是在双堆栈套接字上获取 IPv4 映射的 IPv6 地址,然后尝试在不同的仅 IPv6 套接字上使用返回的 IP 地址。 例如,在双堆栈套接字上使用 时,getocknamegetpeername 函数可以返回 IPv4 映射的 IPv6 地址。 如果随后在未设置为双堆栈的其他套接字上使用返回的 IPv4 映射 IPv6 地址, (IPv6 专用套接字(这是) 创建套接字时的默认行为),则使用此 IPv6 专用套接字和 IPv4 映射的 IPv6 地址将失败。 IPv4 映射的 IPv6 地址格式只能在双堆栈套接字上使用。

在双堆栈数据报套接字上,如果应用程序需要 LPFN_WSARECVMSG (WSARecvMsg) 函数在 WSAMSG 结构中返回通过 IPv4 接收的数据报的数据包信息,则必须在套接字上将 IP_PKTINFO 套接字选项设置为 true。 如果在套接字上仅将 IPV6_PKTINFO 选项设置为 true,则会为通过 IPv6 接收的数据报提供数据包信息,但可能不会为通过 IPv4 接收的数据报提供数据包信息。

如果应用程序尝试在双堆栈数据报套接字上设置 IP_PKTINFO 套接字选项,并且已在系统上禁用 IPv4,则 setsockopt 函数将失败, 并且 WSAGetLastError 将返回 WSAEINVAL 错误。 由于其他错误, setockopt 函数也会返回相同的错误。 如果应用程序尝试在双堆栈套接字上设置IPPROTO_IP级套接字选项,但 WSAEINVAL 失败,则应用程序应确定是否在本地计算机上禁用 IPv4。 可用于检测 IPv4 是启用或禁用的一种方法是调用 套接字 函数,并将 af 参数设置为 AF_INET,以尝试创建 IPv4 套接字。 如果 套接字 函数失败,并且 WSAGetLastError 返回 WSAEAFNOSUPPORT 错误,则表示未启用 IPv4。 在这种情况下,在尝试设置 IP_PKTINFO 套接字选项时 ,setockopt 函数失败可由应用程序忽略。 否则,尝试设置 IP_PKTINFO 套接字选项时失败应被视为意外错误。

对于使用 WSASendMsg 函数发送数据报且应用程序想要指定要使用的特定本地 IP 源地址的双堆栈套接字,处理此方法取决于目标 IP 地址。 在发送到 IPv4 目标地址或 IPv4 映射的 IPv6 目标地址时,在 lpMsg 参数指向的 WSAMSG 结构中传递的一个控制数据对象应包含包含用于发送的本地 IPv4 源地址的in_pktinfo结构。 当发送到不是 IPv4 映射的 IPv6 地址的 IPv6 目标地址时,在 lpMsg 参数指向的 WSAMSG 结构中传递的控制数据对象之一应包含in6_pktinfo结构,其中包含用于发送的本地 IPv6 源地址。

适用于 Windows 套接字应用程序的 IPv6 指南

更改 IPv6 Winsock 应用的数据结构

IPv6 Winsock 应用程序的函数调用

使用硬编码的 IPv4 地址

IPv6 Winsock 应用程序的用户界面问题

IPv6 Winsock 应用程序的基础协议

getpeername

getsockname

in_pktinfo

in6_pktinfo

IP_PKTINFO

IPV6_PKTINFO

setsockopt

LPFN_WSARECVMSG (WSARecvMsg)

WSASendMsg