从主机名解析 IPv6 地址
Resolve IPv6 address from hostname
我们正在更新套接字代码以处理新的 iOS 要求,您需要能够在纯 IPv6 环境中进行连接。
我们目前正在使用 .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 版本不够新。
谢谢
看起来在单声道中,通过 主机名 来创建或连接到服务器将失败。使用直接 IP 始终有效。 Unity 已经很久没有更新 mono socket 的东西了。使用IP没有错。
他们错过了 1 号的 Apple 截止日期。我对您的建议是首先检查您的应用程序是否在 iOS 上 运行,然后对所有内容使用 IPv6。如果 IPv6 失败或 returns null 则使用 IPv4。
It'll only print out the IPv4 IPs, which isn't super helpful.
What am I doing wrong here? How can I get the IPv6 IP from a string
hostname? Or is there a better way to resolve this?
它打印出 IPv4,因为您 not 过滤了它。您必须在每个循环中手动检查 ip 是否为 IPv6。
//IPv4
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
}
//IPv6
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
}
如果使用上述解决方案过滤后仍未找到 IPv6,则意味着您所在的网络 not 支持IPv6。当我这么说时,我指的是您的 ISP。如果您的 ISP 没有为您提供 IPv6,那么您将无法使用 IPv6 连接到另一个 public 服务器。您将只能使用您的 ISP 分配给您的 IPv4 连接到 public 服务器。
要了解这一点,请访问 here and here。它会告诉您是否有 IPv4、IPv6 或两者。
下面的代码是我用来检索本地的通用函数,public 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));
@程序员的代码给出了主机名的 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
上抛出异常
我们正在更新套接字代码以处理新的 iOS 要求,您需要能够在纯 IPv6 环境中进行连接。
我们目前正在使用 .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 版本不够新。
谢谢
看起来在单声道中,通过 主机名 来创建或连接到服务器将失败。使用直接 IP 始终有效。 Unity 已经很久没有更新 mono socket 的东西了。使用IP没有错。
他们错过了 1 号的 Apple 截止日期。我对您的建议是首先检查您的应用程序是否在 iOS 上 运行,然后对所有内容使用 IPv6。如果 IPv6 失败或 returns null 则使用 IPv4。
It'll only print out the IPv4 IPs, which isn't super helpful.
What am I doing wrong here? How can I get the IPv6 IP from a string hostname? Or is there a better way to resolve this?
它打印出 IPv4,因为您 not 过滤了它。您必须在每个循环中手动检查 ip 是否为 IPv6。
//IPv4
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
}
//IPv6
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
}
如果使用上述解决方案过滤后仍未找到 IPv6,则意味着您所在的网络 not 支持IPv6。当我这么说时,我指的是您的 ISP。如果您的 ISP 没有为您提供 IPv6,那么您将无法使用 IPv6 连接到另一个 public 服务器。您将只能使用您的 ISP 分配给您的 IPv4 连接到 public 服务器。
要了解这一点,请访问 here and here。它会告诉您是否有 IPv4、IPv6 或两者。
下面的代码是我用来检索本地的通用函数,public 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));
@程序员的代码给出了主机名的 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