【发布时间】:2010-12-09 17:57:12
【问题描述】:
我目前正在开发一个 UDP 套接字应用程序,我需要构建支持,以便 IPV4 和 IPV6 连接可以将数据包发送到服务器。
我希望有人可以帮助我并指出正确的方向;我发现的大部分文档都不完整。如果您能指出 Winsock 和 BSD 套接字之间的任何区别,那也会很有帮助。
提前致谢!
【问题讨论】:
标签: c++ winsock ipv6 sockets ipv4
我目前正在开发一个 UDP 套接字应用程序,我需要构建支持,以便 IPV4 和 IPV6 连接可以将数据包发送到服务器。
我希望有人可以帮助我并指出正确的方向;我发现的大部分文档都不完整。如果您能指出 Winsock 和 BSD 套接字之间的任何区别,那也会很有帮助。
提前致谢!
【问题讨论】:
标签: c++ winsock ipv6 sockets ipv4
最好的方法是创建一个也可以接受 IPv4 连接的 IPv6 服务器套接字。为此,请创建一个常规 IPv6 套接字,关闭套接字选项 IPV6_V6ONLY,将其绑定到“任意”地址,然后开始接收。 IPv4 地址将以IPv4-mapped 格式显示为 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() 的地址族...并处理。
对于 UDP 实现,我会小心设置双栈套接字,或者更一般地说,绑定到所有接口 (INADDR_ANY)。经典问题是,当地址未锁定(参见bind())到特定接口并且系统有多个接口请求时,响应可能会根据操作系统路由表的突发奇想从具有多个地址的计算机的不同地址传输,令人困惑的应用程序协议——尤其是任何具有身份验证要求的系统。
对于这不成问题的 UDP 实现或 TCP,当您的系统启用 IPv* 时,双堆栈套接字可以节省大量时间。必须注意不要完全依赖双栈,因为这不是绝对必要的,因为不乏使用不支持双栈套接字的 IPv6 栈部署的合理平台(旧 Linux、BSD、Windows 2003)。
【讨论】:
RFC 并没有真正指定 IPV6_V6ONLY 套接字选项的存在,但是,如果它不存在,RFC 非常清楚,实现应该就好像该选项为 FALSE。
如果存在该选项,我认为它应该默认为 FALSE,但出于难以理解的原因,BSD 和 Windows 实现默认为 TRUE。有一个奇怪的说法是,这是一个安全问题,因为不了解 IPv6 的程序员可能会认为他们仅绑定到 IN6ADDR_ANY 以仅用于 IPv6,并意外接受导致安全问题的 IPv4 连接。我认为这既牵强又荒谬,除了让任何期望符合 RFC 实现的人感到惊讶之外。
对于 Windows,不合规通常不会令人意外。在 BSD 的情况下,这充其量是不幸的。
【讨论】:
我一直在 Windows 下玩这个,它实际上似乎是一个安全问题,如果你绑定到环回地址,那么 IPv6 套接字正确绑定到 [::1] 但映射的 IPv4 套接字是绑定到 INADDR_ANY,因此您的(据称)安全的仅限本地应用程序实际上是向世界公开的。
【讨论】: