是否有用于 ipv4 和 ipv6 地址的标准 .NET 解码器?

发布于 2024-10-21 05:23:50 字数 424 浏览 11 评论 0原文

我想编写一个相当简单的客户端-服务器网络应用程序。我只使用纯 IPv4 网络,但如果我的代码能够面向未来,那就太好了。我可能会使用 TcpListener/TcpClient,因为WCF 的初步调查表明它的设置过于复杂且难以理解。

对于客户端,.NET 是否提供了自动解码包含 IPv4 或 IPv6 地址(其中 IPv4 地址包含端口号)的字符串的功能?如果可以解析域名则加分。

对于服务器端,我听说 IPv6 不使用端口号,那么要侦听的端口的等效项是什么?是否有标准方法来区分 IPv4 端口号字符串和 IPv6 等效端口号字符串? 没关系,IPv6 服务和 IPv4 一样也有 16 位端口号。

I'd like to write a fairly simple client-server network app. I only use a pure IPv4 network, but it would be nice to future-proof my code. I'll probably be using TcpListener/TcpClient, because preliminary investigation of WCF reveals it to be overly complex to set up and hard to grok.

For the client side, does .NET provide a facility to automatically decode a string that contains an IPv4 or IPv6 address (where the IPv4 address includes a port number)? Bonus points if it can resolve a domain name.

For the server side, I heard IPv6 doesn't use port numbers, so what's the equivalent of the port to listen on, and is there a standard way to differentiate a IPv4 port number string from the IPv6 equivalent? Never mind, IPv6 services have 16-bit port numbers just like IPv4 ones.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

溺深海 2024-10-28 05:23:50

是的 System.Net.IPAddress

IPAddress.Parse( "fe80::21c:42ff:fe00:8%vnic0" );
IPAddress.Parse( "127.0.0.1" );

并测试 IPv4或 v6

if( IPAddress.Parse(...).AddressFamily == AddressFamily.InterNetwork )
  // IPv4 address

Yep System.Net.IPAddress

IPAddress.Parse( "fe80::21c:42ff:fe00:8%vnic0" );
IPAddress.Parse( "127.0.0.1" );

And to test for IPv4 or v6

if( IPAddress.Parse(...).AddressFamily == AddressFamily.InterNetwork )
  // IPv4 address
温柔女人霸气范 2024-10-28 05:23:50

System.Net.IPAddress 可用于解析表示有效 IPv4 和 IPv6 地址的字符串。
System.Net.Dns 可用于解析网络上的主机名和地址。

对于两者来说,

using System.Net;

System.Net.IPAddress can be used to parse strings representing valid IPv4 and IPv6 addresses.
System.Net.Dns can be used to resolve hostnames and addresses on a network.

For both,

using System.Net;
幼儿园老大 2024-10-28 05:23:50

@Qwertie 说:

由于 IPv6 地址还包含
冒号,我想知道正确的方法是什么
是解码 IPv6 地址或 IPv4 地址
包含端口号的地址。

正如其他人所指出的,端口号不是 IP 地址(IPv4 或 IPv6)的一部分。 IP 地址是原子的无符号整数(IPv4 是 32 位,IPv6 是 128 位)。当以字符形式(例如 URI)表示时,它们可以与端口号(和其他信息)组合。在 URI 中,主机和端口[可以]是 URI 的权限部分的一部分。

URI 可以使用 System.Uri。 URI 的 Authority 部分由以下属性组成:HostPort(以及可选且已弃用的 UserInfo 子组件,由用户名和密码)。属性 HostNameType 将告诉您所拥有的主机名类型,枚举 UriHostNameType 的值:Dns、Ipv4、Ipv6 或其他值。

您还可以使用 RFC 3986 的附录 B 中定义的正则表达式将 URI 解析为其组成部分

Appendix B.  Parsing a URI Reference with a Regular Expression
As the "first-match-wins" algorithm is identical to the "greedy" disambiguation method used by POSIX regular expressions, it is natural and commonplace to use a regular expression for parsing the potential five components of a URI reference.
The following line is the regular expression for breaking-down a well-formed URI reference into its components.
^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#]))?(#(.))? 12 3 4 5 6 7 8 9
The numbers in the second line above are only to assist readability; they indicate the reference points for each subexpression (i.e., each paired parenthesis). We refer to the value matched for subexpression <n> as
lt;n>.  For example, matching the above expression to
http://www.ics.uci.edu/pub/ietf/uri/#Related
results in the following subexpression matches:
$1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = $7 = $8 = #Related $9 = Related
where <undefined> indicates that the component is not present, as is the case for the query component in the above example. Therefore, we can determine the value of the five components as
scheme = $2 authority = $4 path = $5 query = $7 fragment = $9
Going in the opposite direction, we can recreate a URI reference from its components by using the algorithm of Section 5.3.

但请注意,这个正则表达式似乎有点不正确。根据 RFC 3986 及其前身 RFC 2396 的勘误表

Errata ID: 1933
Status: Verified Type: Technical Reported By: Skip Geel Date Reported: 2009-10-25 Verifier Name: Peter Saint-Andre Date Verified: 2010-11-11
Section appendix B says:
^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#]))?(#(.))?
It should say:
/^(([^:\/?#]+):)?(\/\/([^\/?#]))?([^?#])(\?([^#]))?(#(.))?/
Notes:
A Regular Expression is delimited by the slash ("/"). Within it a slash should be preceded by a back-slash ("\").
Peter: This also applies to RFC 3986.

@Qwertie said:

Since IPv6 addresses also contain
colons, I wonder what the proper way
is to decode a IPv6 address or IPv4
address that contains a port number.

As others have noted, a port number is not part of an IP address (either IPv4 or IPv6). IP addresses are atomic, unsigned integers (IPv4 is 32-bit, IPv6 is 128-bit). When represented in character form (such as a URI), they may be combined with a port number (and other information). Within a URI, the host and port are [can be] a part of the authority portion of a URI.

URIs may be parsed into their constituent parts using System.Uri. The Authority portion of a URI is composed of the following properties: Host, Port (and, optionally, and deprecated, the UserInfo subcomponent, consisting of username and password). The property HostNameType will tell you what kind of hostname you've got, a value of the enum UriHostNameType: Dns, Ipv4, Ipv6 or something else.

You can also parse a URI into its component parts using the regular expression defined in Appendix B of RFC 3986:

Appendix B.  Parsing a URI Reference with a Regular Expression
As the "first-match-wins" algorithm is identical to the "greedy" disambiguation method used by POSIX regular expressions, it is natural and commonplace to use a regular expression for parsing the potential five components of a URI reference.
The following line is the regular expression for breaking-down a well-formed URI reference into its components.
^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#]))?(#(.))? 12 3 4 5 6 7 8 9
The numbers in the second line above are only to assist readability; they indicate the reference points for each subexpression (i.e., each paired parenthesis). We refer to the value matched for subexpression <n> as
lt;n>.  For example, matching the above expression to
http://www.ics.uci.edu/pub/ietf/uri/#Related
results in the following subexpression matches:
$1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = $7 = $8 = #Related $9 = Related
where <undefined> indicates that the component is not present, as is the case for the query component in the above example. Therefore, we can determine the value of the five components as
scheme = $2 authority = $4 path = $5 query = $7 fragment = $9
Going in the opposite direction, we can recreate a URI reference from its components by using the algorithm of Section 5.3.

Note though that this regular expression seems to be slightly incorrect. According to the errata for RFC 3986 and its antecedent, RFC 2396:

Errata ID: 1933
Status: Verified Type: Technical Reported By: Skip Geel Date Reported: 2009-10-25 Verifier Name: Peter Saint-Andre Date Verified: 2010-11-11
Section appendix B says:
^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#]))?(#(.))?
It should say:
/^(([^:\/?#]+):)?(\/\/([^\/?#]))?([^?#])(\?([^#]))?(#(.))?/
Notes:
A Regular Expression is delimited by the slash ("/"). Within it a slash should be preceded by a back-slash ("\").
Peter: This also applies to RFC 3986.

離殇 2024-10-28 05:23:50

正如 Paul 提到的,没有端口号的纯 IP 地址可以通过 IPAddress.Parse() 进行解析。但是,如果存在端口号和/或主机名(12.34.56.78:90 或 www.example.com:5555),则需要采用不同的方法。如果您想使用 TcpClient 进行连接,此函数将这样做:

public static TcpClient Connect(string ipAndPort, int defaultPort)
{
    if (ipAndPort.Contains("/"))
        throw new FormatException("Input should only be an IP address and port");

    // Uri requires a prefix such as "http://", "ftp://" or even "foo://".
    // Oddly, Uri accepts the prefix "//" UNLESS there is a port number.
    Uri uri = new Uri("tcp://" + ipAndPort);

    string ipOrDomain = uri.Host;
    int port = uri.Port != -1 ? uri.Port : defaultPort;
    return new TcpClient(ipOrDomain, port);
}

defaultPort 参数指定在输入字符串没有端口时要使用的端口。例如:

using (NetworkStream s = Connect("google.com", 80).GetStream())
{
    byte[] line = Encoding.UTF8.GetBytes("GET / HTTP/1.0\r\n\r\n");
    s.Write(line, 0, line.Length);

    int b;
    while ((b = s.ReadByte()) != -1)
        Console.Write((char)b);
}

要在不连接的情况下解码地址(例如,验证它是否有效,或者因为您通过需要 IP 地址的 API 进行连接),此方法将这样做(并可选择执行 DNS 查找):

public static IPAddress Resolve(string ipAndPort, ref int port, bool resolveDns)
{
    if (ipAndPort.Contains("/"))
        throw new FormatException("Input address should only contain an IP address and port");

    Uri uri = new Uri("tcp://" + ipAndPort);

    if (uri.Port != -1)
        port = uri.Port;
    if (uri.HostNameType == UriHostNameType.IPv4 || uri.HostNameType == UriHostNameType.IPv6)
        return IPAddress.Parse(uri.Host);
    else if (resolveDns)
        return Dns.GetHostAddresses(uri.Host)[0];
    else
        return null;
}

奇怪的是, Dns.GetHostAddresses 可以返回多个地址。我询问了,并且显然,只需获取第一个地址就可以了。

如果存在语法错误或解析域名时出现问题(FormatExceptionSocketException),则会引发异常。如果用户指定了域名,但 resolveDns==false,则此方法返回 null

As Paul mentioned, a plain IP Address with no port number can be parsed by IPAddress.Parse(). However, if there is a port number and/or hostname (12.34.56.78:90 or www.example.com:5555), a different approach is needed. If you want to use TcpClient to connect, this function will do so:

public static TcpClient Connect(string ipAndPort, int defaultPort)
{
    if (ipAndPort.Contains("/"))
        throw new FormatException("Input should only be an IP address and port");

    // Uri requires a prefix such as "http://", "ftp://" or even "foo://".
    // Oddly, Uri accepts the prefix "//" UNLESS there is a port number.
    Uri uri = new Uri("tcp://" + ipAndPort);

    string ipOrDomain = uri.Host;
    int port = uri.Port != -1 ? uri.Port : defaultPort;
    return new TcpClient(ipOrDomain, port);
}

The defaultPort parameter specifies the port to use if the input string doesn't have one. For example:

using (NetworkStream s = Connect("google.com", 80).GetStream())
{
    byte[] line = Encoding.UTF8.GetBytes("GET / HTTP/1.0\r\n\r\n");
    s.Write(line, 0, line.Length);

    int b;
    while ((b = s.ReadByte()) != -1)
        Console.Write((char)b);
}

To decode the address without connecting to it (e.g. to verify that it is valid, or because you are connecting via an API that requires an IP address), this method will do so (and optionally perform DNS lookup):

public static IPAddress Resolve(string ipAndPort, ref int port, bool resolveDns)
{
    if (ipAndPort.Contains("/"))
        throw new FormatException("Input address should only contain an IP address and port");

    Uri uri = new Uri("tcp://" + ipAndPort);

    if (uri.Port != -1)
        port = uri.Port;
    if (uri.HostNameType == UriHostNameType.IPv4 || uri.HostNameType == UriHostNameType.IPv6)
        return IPAddress.Parse(uri.Host);
    else if (resolveDns)
        return Dns.GetHostAddresses(uri.Host)[0];
    else
        return null;
}

Curiously, Dns.GetHostAddresses can return multiple addresses. I asked about it, and apparently it's okay to simply take the first address.

An exception will be raised if there is a syntax error or a problem resolving the domain name (FormatException or SocketException). If the user specified a domain name but resolveDns==false, this method returns null.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文