UDP client/server:混合使用 IPv4 和 IPv6?

UDP client/server: Mix IPv4 and IPv6?

假设您有一个游戏服务器,只有 UDP,运行 在一个同时具有 IPv4 和 IPv6 地址的服务器上。服务器启动,调用 getaddrinfo() 以遍历可用地址,假设它获取 IPv6 地址。因此它在 IPv6 上创建套接字并等待来自客户端的数据包。

客户端尝试连接,但这次它使用的是用户输入的 IPv4 地址。它创建一个 IPv4 套接字,并尝试连接到服务器。区别真的很重要吗?或者 IPv4 套接字和 IPv6 套接字之间的区别是否仅限于本地机器?

同样,如果客户端已经创建了一个 IPv6 套接字供使用(因为 getaddrinfo() 表示它是有效的),然后它调用 getaddrinfo() 来查找服务器地址,如果它只获取IPv4 结果?我知道我可以告诉 getaddrinfo() 只给出 IPv6 结果,但是如果服务器没有 IPv6 地址怎么办? UDP 客户端是否应该关闭并重新创建它们的套接字以匹配服务器地址格式?或者我能保证得到我要求的地址格式吗?

(我欢迎任何回答这些问题的文档参考。我已经研究了几个小时,但还没有找到这些问题的明确答案。)

默认情况下,IPv6 UDP 套接字将仅发送和接收 IPv6 UDP 数据包,因此您的 IPv4 客户端将不走运。

但是,如果您 运行 在双栈计算机上(您可能是),则可以在套接字上启用 IPv4-mapped IPv6 addresses,然后您可以使用该套接字来处理两者IPv4 和 IPv6 UDP 流量。 IPv4 数据包将显示为来自特殊格式的 IPv6 地址(格式如“::ffff:192.168.0.5”),但除此之外它们的处理方式与任何 IPv6 UDP 客户端相同。

您可以像这样在套接字上启用 IPv4 映射的 IPv6 地址:

int v6OnlyEnabled = 0;  // we want v6-only mode disabled, which is to say we want v6-to-v4 compatibility
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &v6OnlyEnabled, sizeof(v6OnlyEnabled)) != 0) perror("setsockopt");

另一种方法是根据需要创建单独的 IPv4 和 IPv6 套接字(在客户端 and/or 服务器上),但只要您有可用的双栈网络堆栈,IPv4 映射的 IPv6 -地址方法更容易使用。