从主机名解析IPv6地址



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

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

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

如果我使用:

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

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

如果我使用:

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版本还不够新。

感谢

@程序员的代码给出了主机名的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 上引发异常

在mono中,传递主机名以创建或连接到服务器将失败。使用直接IP始终有效。Unity已经很久没有更新单声道插座了。使用IP没有错。

他们错过了苹果公司1日的最后期限。我给你的建议是,首先检查你的应用程序是否在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的公共服务器。

为此,请访问这里和这里。它会告诉您是否具有IPv4IPv6或两者兼有。

下面的代码是我用来检索本地公共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));

最新更新