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

时间:2011-03-11 18:48:59

标签: .net ipv6 ipv4

我想写一个相当简单的客户端 - 服务器网络应用程序。我只使用纯粹的IPv4网络,但是对于面向未来的代码我会很高兴。我可能会使用TcpListener / TcpClient,因为preliminary investigation of WCF显示它设置过于复杂并且难以理解。

对于客户端,.NET是否提供了自动解码包含IPv4或IPv6地址的字符串(IPv4地址包含端口号)的工具?奖励积分,如果它可以解析域名。

对于服务器端,我听说IPv6不使用端口号,那么相当于要侦听的端口是什么,有没有一种标准方法可以区分IPv4端口号字符串和IPv6等价物? 没关系,IPv6服务有16位端口号,就像IPv4服务器一样。

4 个答案:

答案 0 :(得分:6)

是的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

答案 1 :(得分:2)

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

对于两者,

using System.Net;

答案 2 :(得分:2)

@Qwertie说:

  

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

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

可以使用System.Uri将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 $<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的errata及其前因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.

答案 3 :(得分:0)

正如Paul所提到的,IPAddress.Parse()可以解析没有端口号的普通IP地址。但是,如果有端口号和/或主机名(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可以返回多个地址。我asked about it,显然只需要取第一个地址就可以。

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