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 上的端口的主要内容,如果未能解决你的问题,请参考以下文章