【问题标题】:Resolve IPv6 address from hostname从主机名解析 IPv6 地址
【发布时间】:2016-06-06 16:16:53
【问题描述】:

我们正在更新我们的套接字代码,以处理您需要能够在纯 IPv6 环境中连接的新 iOS 要求。

我们目前正在使用 .NET 套接字和 TcpClient。

我正在尝试建立一个 IPv6 和 IPv4 都可以工作的解决方案,但到目前为止什么都没有发生。

如果我使用:

TcpClient client = new TcpClient();
client.BeginConnect( "server.hostname.com", 8182, this._onConnect, client );

在 IPv6 环境中,我没有得到响应; _onConnect 方法永远不会被触发。

如果我使用:

TcpClient client = new TcpClient( AddressFamily.InterNetworkV6 );
client.BeginConnect( "server.hostname.com", 8182,this._onConnect, client);

我收到SocketException:

An address incompatible with the requested protocol was used (errorCode: 10047, socketErrorCode: AddressFamilyNotSupported, nativeErrorCode: 10047)

这很烦人,如果可以理解的话。如果我使用:

TcpClient client = new TcpClient( AddressFamily.InterNetworkV6 );
client.BeginConnect( "xxxx:xxxx:xxxx::xxxx:xxxx", 8182,this._onConnect, client);

然后我可以连接,但是:

  • 我现在输入的是原始 IP 地址而不是主机名,这不好
  • 这将不再适用于 IPv4 环境

所以我想我可以从主机名中获取支持的 IP,并尝试一个接一个地连接。

使用此代码:

IPHostEntry hostInfo = Dns.GetHostEntry( "server.hostname.com" );
foreach(IPAddress ip in hostInfo.AddressList)
    Debug.Log( "Ip: " + ip.ToString() + ": address family: " + ip.AddressFamily );

它只会打印出 IPv4 IP,这不是很有帮助。

我在这里做错了什么?如何从字符串主机名中获取 IPv6 IP?或者有没有更好的方法来解决这个问题?

我有点假设这会在 DNS 级别自动解析,但我猜 Unity 中包含的 Mono 版本不够最新。

谢谢

【问题讨论】:

标签: c# unity3d mono


【解决方案1】:

@Programmer 的代码给出了主机名的 IP 地址,但我想澄清两件事。

1) 代码:

TcpClient client = new TcpClient( AddressFamily.InterNetworkV6 );
client.BeginConnect( "server.hostname.com", 8182,this._onConnect, client);

确实工作,但只在 iOS 上。在编辑器和 Android 上,它给出了一个例外(从 Unity 5.3.5f1 开始)。这似乎是实现中的一个错误,所以我已经发送了一个错误报告。

2) 尽管System.Net.Sockets.Socket.SupportsIPv6 被标记为已过时并且Unity 建议您使用System.Net.Sockets.Socket.OSSupportsIPv6,但OSSupportsIPv6 将在Android 上引发异常

【讨论】:

  • 深入研究后发现问题出在“.Net 2.0”和“.Net 2.0 Subset”的兼容级别上。子集有效,而完整则无效。更改为子集,我现在可以使用主机名,Socket.OSSupportsIPv6 不再引发异常 - 错误报告:fogbugz.unity3d.com/default.asp?804510_c5ei44diq6ktnh1u
【解决方案2】:

看起来像在单声道中,传递 主机名 来创建或连接到服务器会失败。使用直接 IP 始终有效。 Unity 很久没有更新单插座的东西了。使用IP没有任何问题。

错过了 1 日的 Apple 截止日期。我对您的建议是首先检查您的应用程序是否在 iOS 上运行,然后对所有内容使用 IPv6。如果 IPv6 失败或返回 null,则使用 IPv4。

它只会打印出 IPv4 IP,这不是很有帮助。

我在这里做错了什么?如何从字符串中获取 IPv6 IP 主机名?或者有没有更好的方法来解决这个问题?

它正在打印出 IPv4,因为您没有没有过滤它。您必须在每个循环中手动检查 ip 是否为 IPv6。

//IPv4
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
}

//IPv6
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
}

如果 IPv6 即使在使用上述解决方案将其过滤掉后仍找不到,则表示您所在的网络不支持 IPv6强>。当我这么说时,我的意思是您的 ISP。如果您的 ISP 没有为您提供 IPv6,那么您将无法使用 IPv6 连接到另一台公共服务器。您只能使用您的 ISP 分配给您的 IPv4 连接到公共服务器。

为此,请访问here 和here。它会告诉您是否拥有 IPv4、IPv6 或两者兼有。

下面的代码是我用来检索本地公共 IP 的通用函数,包括版本 4 和 6。

private string getIPAddress(string hostName, IPTYPE ipType, ADDRESSFAM Addfam)
    {
        //Return null if ADDRESSFAM is Ipv6 but Os does not support it
        if (Addfam == ADDRESSFAM.IPv6 && !System.Net.Sockets.Socket.OSSupportsIPv6)
        {
            return null;
        }

        //////////////HANDLE LOCAL IP(IPv4 and IPv6)//////////////
        if (ipType == IPTYPE.LOCAL_IP)
        {

            System.Net.IPHostEntry host;
            string localIP = "";
            host = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
            foreach (System.Net.IPAddress ip in host.AddressList)
            {
                //IPv4
                if (Addfam == ADDRESSFAM.IPv4)
                {
                    if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        localIP = ip.ToString();
                    }
                }

                 //IPv6
                else if (Addfam == ADDRESSFAM.IPv6)
                {
                    if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                    {
                        localIP = ip.ToString();
                    }
                }
            }
            return localIP;

        }

        //////////////HANDLE PUBLIC IP(IPv4 and IPv6)//////////////
        if (ipType == IPTYPE.PUBLIC_IP)
        {
            //Return if hostName String is null
            if (string.IsNullOrEmpty(hostName))
            {
                return null;
            }

            System.Net.IPHostEntry host;
            string localIP = "";
            host = System.Net.Dns.GetHostEntry(hostName);
            foreach (System.Net.IPAddress ip in host.AddressList)
            {
                //IPv4
                if (Addfam == ADDRESSFAM.IPv4)
                {
                    if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        localIP = ip.ToString();
                    }
                }

                //IPv6
                else if (Addfam == ADDRESSFAM.IPv6)
                {
                    if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                    {
                        localIP = ip.ToString();
                    }
                }

            }
            return localIP;
        }
        return null;
    }


    enum IPTYPE
    {
        LOCAL_IP, PUBLIC_IP
    }

    enum ADDRESSFAM
    {
        IPv4, IPv6
    }

用法:

    Debug.Log("Local IPv4: " + getIPAddress("", IPTYPE.LOCAL_IP, ADDRESSFAM.IPv4));
    Debug.Log("Local IPv6: " + getIPAddress("", IPTYPE.LOCAL_IP, ADDRESSFAM.IPv6));

    Debug.Log("Public IPv4: " + getIPAddress("google.com", IPTYPE.PUBLIC_IP, ADDRESSFAM.IPv4));
    Debug.Log("Public IPv6: " + getIPAddress("google.com", IPTYPE.PUBLIC_IP, ADDRESSFAM.IPv6));

【讨论】:

  • 谢谢你,我解决了这个问题,因为后端的 iOS 代码似乎不同。我已经接受了答案,因为它回答了这个问题,但长话短说,主机名 will 在 iOS 中工作,但在编辑器和 android 中抛出异常。我已经打开了一个统一的错误
  • 另外,System.Net.Sockets.Socket.OSSupportsIPv6 在 Android 上引发异常 - 它可能是相关的。 SupportsIPv6 似乎有效,但它被标记为过时
  • @divillysausages 是的,这是一个错误,我不再依赖直接使用主机名。我不会使用适用于一个操作系统但不适用于另一个操作系统的代码。无论如何,如果抛出异常,请从获取 IP 函数中删除 System.Net.Sockets.Socket.SupportsIPv6。 Kudo 用于打开错误。确保也在这里发布您的错误blogs.unity3d.com/2016/05/10/unity-and-ipv6-support。如果您在此处发布该网络错误,Unity 将在此时认真对待,因为 Apple 提出了这一要求,并且 Unity 确保没有人的应用程序因为他们的错误而被拒绝或丢弃。
猜你喜欢
  • 2013-02-28
  • 1970-01-01
  • 2013-03-25
  • 2013-05-04
  • 2011-08-21
  • 2011-03-12
  • 2014-02-26
  • 2014-10-13
  • 2013-01-29
相关资源
最近更新 更多