【问题标题】:What dictates the formatting of IPv6 addresses by System.Net.IPAddress.ToString()?什么决定了 System.Net.IPAddress.ToString() 对 IPv6 地址的格式?
【发布时间】:2011-06-19 07:11:43
【问题描述】:

内置的 .Net 方法 System.Net.IPAddress.ToString() 对于 IPv6 地址的行为不一致。

给定字节数组0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,在某些环境中返回"aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa",而在其他环境中返回"aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:172.172.172.172"

我知道这两种格式都是有效的 IPv6 格式,但我希望能够解释其中的区别。

似乎较新的环境(Windows 7 和 Server 2008 R2)更有可能产生第一个行为,因此我检查了 .Net 框架版本等明显差异,但我无法检测到模式。

有没有一种方法可以让我选择一种格式而不是另一种格式,或者我是否必须围绕这个进行编码才能获得一致的行为?

要重新创建的代码:

    byte[] bytes = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
    IPAddress myIP = new IPAddress(bytes);
    Console.WriteLine(myIP.ToString());

【问题讨论】:

    标签: .net ip-address ipv6


    【解决方案1】:

    使用Reflector 在 ToString 的内部进行探索,您可以看到,如果确定操作系统支持 IPv6(对于某些支持值),那么它将遵循名为 WSAAddressToString 的 Win32 函数,而如果这个标志没有设置,它手动格式化(从它的内部字节数组):

    addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[0] })).Append(':');
    addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[1] })).Append(':');
    addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[2] })).Append(':');
    addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[3] })).Append(':');
    addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[4] })).Append(':');
    addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[5] })).Append(':');
    addressString.Append((int) ((this.m_Numbers[6] >> 8) & 0xff)).Append('.');
    addressString.Append((int) (this.m_Numbers[6] & 0xff)).Append('.');
    addressString.Append((int) ((this.m_Numbers[7] >> 8) & 0xff)).Append('.');
    addressString.Append((int) (this.m_Numbers[7] & 0xff));
    

    这将始终返回您显示的第二种格式。

    是否设置了“OS 支持 IPv6”标志似乎取决于类内的内部知识(版本必须> 2000),并且它似乎是创建 IPv6 套接字的实际尝试 - 所以如果你在 XP禁用 IPv6 的机器,我想你也会得到第二种格式。

    【讨论】:

      【解决方案2】:

      在某些情况下,它不依赖于操作系统支持 IPv6 标志。我在 windows server 2008 R2 上遇到了这个问题。我试过这个

        String ipString = "2400:3C00:3FFE:0000:0000:5EFE:8999:48AA";
        System.Net.IPAddress address;
        IPAddress.TryParse(ipString, out address);
      

      但 address.ToString() 返回值“2400:3c00:3ffe::5efe:137.153.72.170”。

      但是,如果我将 IP 字符串更改为“2400:3C00:3FFE:1000:1000:5EFE:8999:48AA”,它会正常工作。

      【讨论】:

        【解决方案3】:

        在我的例子中,我需要确保格式一致,而不需要对 WSAAddressToString 进行非托管 API 调用,因此我编写了以下扩展方法。也许这会对将来的某人有所帮助:

        /// <summary>
        /// Returns the IPv4 or IPv6 address in standard notation. Any transitional suffix (i.e. an IPv4-like address
        /// displayed in place of the final two segments of an IPv6 address) returned by .NET is converted to standard colon notation.
        /// See http://stackoverflow.com/questions/4863352/what-dictates-the-formatting-of-ipv6-addresses-by-system-net-ipaddress-tostring.
        /// </summary>
        public static string ToStringNonTransitional(this System.Net.IPAddress oIPAddress)
        {
            var sIP = oIPAddress.ToString();
        
            if (oIPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                return sIP; // Return IPv4 addresses untouched.
        
            if (oIPAddress.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
                throw new Exception(string.Format("Can't handle '{0}' in '{1}' format. (Only IPv4 or IPv6 supported.)", sIP, oIPAddress.AddressFamily.ToString()));
        
            if (!sIP.Contains("."))
                return sIP;
        
            try
            {
                var iTransitionalStart = sIP.LastIndexOf(":") + 1;
                var sTransitionalPart = sIP.Substring(iTransitionalStart);
                sIP = sIP.Substring(0, iTransitionalStart);
                var asOctects = sTransitionalPart.Split('.');
                sIP += string.Format("{0:x2}{1:x2}", Convert.ToInt16(asOctects[0]), Convert.ToInt16(asOctects[1])).TrimStart('0');
                sIP += ":" + string.Format("{0:x2}{1:x2}", Convert.ToInt16(asOctects[2]), Convert.ToInt16(asOctects[3])).TrimStart('0');
        
                return sIP;
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to convert IPv6 address to standard notation: " + sIP, ex);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2011-08-10
          • 2021-12-21
          • 1970-01-01
          • 2020-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-11
          相关资源
          最近更新 更多