【问题标题】:Is there a standard .NET decoder for ipv4 and ipv6 addresses?是否有用于 ipv4 和 ipv6 地址的标准 .NET 解码器?
【发布时间】:2011-07-13 17:16:54
【问题描述】:

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

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

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

【问题讨论】:

    标签: .net ipv6 ipv4


    【解决方案1】:

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

    【讨论】:

    • IPAddress.Parse("23.45.67.89:1024") 抛出 FormatException,所以我猜答案是“有点”。
    • 这不是一个有效的 IP 地址。端口号不是 TCP/IP 堆栈的 IP 部分的一部分。 IP 地址没有端口。您正在使用的更接近 URI 也可以使用 Uri 类进行解析。
    • 由于 IPv6 地址也包含冒号,我想知道解码包含端口号的 IPv6 地址或 IPv4 地址的正确方法是什么。也许可以从 IPAddress.TryParse 开始,如果失败,请查找端口号,解析它,删除它,然后重试。如果仍然失败,请使用 System.Net.Dns.Resolve 解析为域名——但我很困惑,因为它返回的 IPHostEntry 可以包含多个 IP 地址。从什么时候开始一个域名有多个IP地址?我们应该尝试连接到所有这些吗?
    • IP 地址不包含端口号 - 在 v4 或 v6 中。您正在尝试解析使用 ip 地址作为主机名的 URI。只需使用 Uri 即可。
    【解决方案2】:

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

    对于两者来说,

    using System.Net;
    

    【讨论】:

    • 你不会提到调用哪些方法?
    • IPAddress.Parse()(或 IPAddress.TryParse())和 Dns.GetHostEntry()
    【解决方案3】:

    @Qwertie 说:

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

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

    可以使用System.Uri 将URI 解析为其组成部分。 URI 的Authority 部分由以下属性组成:Host、Port(以及可选且已弃用的 UserInfo 子组件,由用户名和密码组成)。 HostNameType 属性会告诉你你有什么样的主机名,枚举 UriHostNameType 的值:Dns、Ipv4、Ipv6 或其他。

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

    附录 B. 使用正则表达式解析 URI 引用
    由于“第一场比赛获胜”算法与“贪婪”算法相同 POSIX正则表达式使用的消歧方法,它是 使用正则表达式解析 URI 引用的潜在五个组成部分。
    以下行是用于分解 a 的正则表达式 对其组件的格式良好的 URI 引用。
    ^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#] ))?(#(.))? 12 3 4 5 6 7 8 9
    上面第二行的数字只是为了便于阅读; 它们指示每个子表达式的参考点(即,每个 双括号)。我们指的是子表达式匹配的值 为 $。例如,将上面的表达式匹配到
    http://www.ics.uci.edu/pub/ietf/uri/#Related
    导致以下子表达式匹配:
    $1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = 7 美元 = $8 = #相关 $9 = 相关
    其中 表示组件不存在,原样 上例中查询组件的情况。因此,我们 可以将五个分量的值确定为
    方案 = $2 权限 = 4 美元 路径 = $5 查询 = $7 片段 = $9
    反过来,我们可以重新创建一个 URI 引用 其组件使用第 5.3 节的算法。

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

    勘误 ID:1933
    状态:已验证 类型:技术 报告人:跳过 Geel 报告日期:2009-10-25 验证人姓名:Peter Saint-Andre 验证日期:2010-11-11
    附录 B 部分说:
    ^(([^:/?#]+):)?(//([^/?#]))?([^?#])(\?([^#] ))?(#(.))?
    它应该说:
    /^(([^:\/?#]+):)?(\/\/([^\/?#]))?([^?#])(\? ([^#]))?(#(.))?/
    备注:
    正则表达式由斜杠 ("/") 分隔。里面有一个斜线 前面应该有一个反斜杠(“\”)。
    Peter:这也适用于 RFC 3986。

    【讨论】:

    • 原始的正则表达式对于 .NET 来说看起来不错。唯一的区别似乎是第二个版本是斜杠分隔的,因此需要额外的反斜杠。
    【解决方案4】:

    正如 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 可以返回多个地址。我asked about it,显然可以直接取第一个地址。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-18
      • 1970-01-01
      • 2013-07-02
      相关资源
      最近更新 更多