我目前正在开发一个 UDP 套接字应用程序,我需要构建支持,以便 IPV4 和 IPV6 连接可以将数据包发送到服务器。
我希望有人可以帮助我并指出正确的方向;我发现的大部分文档都不完整。如果您能指出 Winsock 和 BSD 套接字之间的任何区别,那也会很有帮助。
提前致谢!
最好的方法是创建一个也可以接受 IPv4 连接的 IPv6 服务器套接字。为此,请创建一个常规 IPv6 套接字,关闭套接字选项IPV6_V6ONLY
,将其绑定到“任意”地址,然后开始接收。IPv4 地址将以IPv4 映射格式显示为 IPv6 地址。
系统之间的主要区别IPV6_V6ONLY
在于 a) 是否可用,以及 b) 默认情况下是打开还是关闭。它在 Linux 上默认关闭(即允许不使用 setsockopt 的双栈套接字),而在大多数其他系统上打开。
此外,Windows XP 上的 IPv6 堆栈不支持该选项。在这些情况下,您将需要创建两个单独的服务器套接字,并将它们放入 select 或多个线程中。
套接字 API 由 IETF RFC 管理,并且在包括 windows WRT IPv6 在内的所有平台上都应该是相同的。
对于 IPv4/IPv6 应用程序来说,一切都getaddrinfo()
与getnameinfo()
. getaddrinfo
是个天才——查看客户端的 DNS、端口名称和功能来解决“我可以使用 IPv4、IPv6 还是两者都使用来到达特定目的地?”这个永恒的问题。或者,如果您要使用双栈路由并希望它返回 IPv4 映射的 IPv6 地址,它也会这样做。
它提供了一个sockaddr *
可以插入到bind()
、recvfrom()
和sendto()
地址族的直接结构……在许多情况下,这意味着无需填写和处理socket()
杂乱的结构。sockaddr_in(6)
对于 UDP 实现,我会小心设置双栈套接字,或者更一般地说,绑定到所有接口 ( INADDR_ANY
)。经典问题是,当地址未锁定(请参阅bind()
)到特定接口并且系统有多个接口请求时,响应可能会根据操作系统路由表的奇思妙想从具有多个地址的计算机的不同地址传输,从而混淆应用程序协议——尤其是任何有身份验证要求的系统。
对于这不是问题的 UDP 实现或 TCP,当您的系统启用 IPv* 时,双堆栈套接字可以节省大量时间。必须小心不要完全依赖双栈,因为它不是绝对必要的,因为不缺乏部署了不支持双栈套接字的 IPv6 栈的合理平台(旧 Linux、BSD、Windows 2003)。
我一直在 Windows 下玩这个,它实际上似乎是一个安全问题,如果你绑定到环回地址,那么 IPv6 套接字正确绑定到 [::1] 但映射的 IPv4 套接字绑定到 INADDR_ANY ,因此您的(据称)安全的仅限本地应用程序实际上已向世界公开。
RFC 并没有真正指定 IPV6_V6ONLY 套接字选项的存在,但是,如果它不存在,RFC 非常清楚,实现应该就好像该选项为 FALSE。
在存在该选项的情况下,我认为它应该默认为 FALSE,但是,出于难以理解的原因,BSD 和 Windows 实现默认为 TRUE。有一个奇怪的说法是,这是一个安全问题,因为不了解 IPv6 的程序员可能会认为他们只绑定到 IN6ADDR_ANY 仅用于 IPv6,并意外接受导致安全问题的 IPv4 连接。我认为这既牵强又荒谬,除了让任何期望符合 RFC 实现的人感到惊讶之外。
在 Windows 的情况下,不合规通常不会令人意外。在 BSD 的情况下,这充其量是不幸的。