IPAddress.Parse() 使用 IPv4 上的端口

Posted

技术标签:

【中文标题】IPAddress.Parse() 使用 IPv4 上的端口【英文标题】:IPAddress.Parse() using port on IPv4 【发布时间】:2011-06-25 12:34:22 【问题描述】:

我正在尝试使用 IPAddress.Parse 解析包含 IP 地址和端口的字符串。这适用于 IPv6 地址,但不适用于 IPv4 地址。有人能解释一下为什么会这样吗?

我使用的代码是:

IPAddress.Parse("[::1]:5"); //Valid
IPAddress.Parse("127.0.0.1:5"); //null

【问题讨论】:

第二个例子我没有得到空值。我得到一个例外。 IPv4 地址不包括端口号。请注意,您正在尝试解析包含“IP 地址 端口”的字符串。所以这个例外是有道理的。为什么 IPv6 版本有效,我不知道。 IPAddress.Parse("[::1]:5"); 是有效的,但是 :5 被默默地丢弃了!如果您检查生成的对象,您可以看到结果只是::1。这实际上可能是IPAddress.Parse 方法中的一个错误... @Martinho Fernandes - 这不是 IP6 解析器中的错误,[::1]:5 是有效的 IP6 地址,因为分隔符是 ':',而不是 '::' (tools.ietf.org/html/… ) - and 组合端口也内置在 IP6 规范中,但是 IPAddress 实体本身不应包含端口。有可能 [a,b,c,d]:port for ipv4 也是允许的,因为 IP6 规范似乎表明它是 IP4 规范的一部分 @Andras:::1:5 确实是一个有效的 IPv6 地址,但与[::1]:5 不同,后者是地址::1 上的端口5。由于“IP 地址”不是“IP 地址和端口”,我认为例外是正确的行为,至少与 IPv4 匹配(顺便说一句 [a.b.c.d]:port 也会抛出)。该端口是 IPv6 协议的一部分,但不是 IPv6 地址的一部分。 @Martinho Fernandes- 其实我的意思是直接在@hangy 发表评论,对不起! :$- 作为一个书呆子,它是 IPv6 的有效文本表示。如果您阅读 IPv6 RFC,它特别允许使用端口编码的 IP6 地址作为 文本表示的一部分。它并没有说必须保留端口(显然不能) - 但它定义了解析时应该如何处理它。具有讽刺意味的是,如果 IPv4 规范也允许这样做,那么 MS 应该更新 IPv4 代码以支持它;或者没有编写 IPv6 解析器来支持它,而不是做半生不熟的工作:) 【参考方案1】:

如果您使用旧版本的 .net,您可以从开源获取 IPEndPoint.Parse 实现:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Primitives/src/System/Net/IPEndPoint.cs

【讨论】:

【参考方案2】:

正如 Tedd Hansen 所指出的,您要解析的不是 IP 地址,而是 IP 端点(IP 地址 + 端口)。从 .NET Core 3.0 开始,您可以使用IPEndPoint.TryParse 将字符串解析为 IPEndPoint:

if (IPEndPoint.TryParse("127.0.0.1:5", out IPEndPoint endpoint))

    // parsed successfully, you can use the "endpoint" variable
    Console.WriteLine(endpoint.Address.ToString()); // writes "127.0.0.1"
    Console.WriteLine(endpoint.Port.ToString()); // writes "5"

else

    // failed to parse

【讨论】:

【参考方案3】:
Uri url;
IPAddress ip;
if (Uri.TryCreate(String.Format("http://0", "127.0.0.1:5"), UriKind.Absolute, out url) &&
   IPAddress.TryParse(url.Host, out ip))

    IPEndPoint endPoint = new IPEndPoint(ip, url.Port);

【讨论】:

请注意,这不适用于没有 [] 的 IPv6,例如 ::1:1024 IPEndPoint.TryParse ?【参考方案4】:

IPAddress 不是 IP+端口。你想要 IPEndPoint。

来自http://www.java2s.com/Code/CSharp/Network/ParseHostString.htm的示例

public static void ParseHostString(string hostString, ref string hostName, ref int port)

   hostName = hostString;
   if (hostString.Contains(":"))
   
      string[] hostParts = hostString.Split(':');

      if (hostParts.Length == 2)
      
         hostName = hostParts[0];
         int.TryParse(hostParts[1], out port);
      
   

编辑:好的,我承认这不是最优雅的解决方案。试试我写的这个(只为你):

// You need to include some usings:
using System.Text.RegularExpressions;
using System.Net;

// Then this code (static is not required):
private static Regex hostPortMatch = new Regex(@"^(?<ip>(?:\[[\da-fA-F:]+\])|(?:\d1,3\.)3\d1,3)(?::(?<port>\d+))?$", System.Text.RegularExpressions.RegexOptions.Compiled);
public static IPEndPoint ParseHostPort(string hostPort)

   Match match = hostPortMatch.Match(hostPort);
   if (!match.Success)
      return null;

   return new IPEndPoint(IPAddress.Parse(match.Groups["ip"].Value), int.Parse(match.Groups["port"].Value));

请注意,这个只接受 IP 地址,不接受主机名。如果您想支持主机名,则必须将其解析为 IP 或不使用 IPAddress/IPEndPoint。

【讨论】:

感谢您的努力,但我已经使用 Uri 类为我的问题提出了解决方案。我只是对为什么 IPAddress.Parse 在这两种情况下的行为很感兴趣。 您的第二个代码示例的 RegEx 甚至不匹配最基本的端点 127.0.0.1:80 第一个解决方案是最好的。如果它不看起来聪明也没关系。【参考方案5】:

这是因为端口不是 IP 地址的一部分。它属于 TCP/UDP,您必须先将其剥离。 Uri 类可能对此有所帮助。

【讨论】:

+1 因为它回答了“为什么?”这个问题。 @Francisco Silva - 然后你可以看到 @abatischev 或 @Tedds 的答案,了解如何处理 有趣的想法是先在上面使用Uri【参考方案6】:

IPAddress.Parse 旨在采用一个字符串,该字符串包含一个 IP 地址,对于 IPv4,采用点分四进制表示法,对于 IPv6,采用冒号-十六进制表示法。因此,您的第一个示例适用于 IPv6,而您的第二个示例失败,因为它不支持 IPv4 端口。链接http://msdn.microsoft.com/en-us/library/system.net.ipaddress.parse.aspx

【讨论】:

以上是关于IPAddress.Parse() 使用 IPv4 上的端口的主要内容,如果未能解决你的问题,请参考以下文章

来自字符串的 C# IPAddress [关闭]

tcplistener 没有启动

转MaxScript.Net接收本地端口的消息执行

SuperSocket1.6Code解析

IP地址'::1'是啥?

C# IP地址和DNS 网络