65.9K
CodeProject 正在变化。 阅读更多。
Home

扩展 IPAddress 对象以允许对两个 IP 地址进行相对比较

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.92/5 (5投票s)

2008年6月1日

CPOL

3分钟阅读

viewsIcon

38654

downloadIcon

310

本文概述了如何扩展 IPAddress 对象,以提供对两个 IP 地址进行相对数值比较的附加功能。

引言

有时需要确定两个 IP 地址的相对位置,或者某个特定 IP 地址是否落在特定范围内。 在 1.0 和 1.1 框架中,IPAddress 对象有一个“Address”属性。 这返回一个 long 值作为 IP 地址的表示,并允许简单地对 IP 地址进行数值比较以确定它们的相对值。

在 2.0 框架中,Address 属性已被弃用。 这可能是由于对 IPv6 寻址的支持的出现。 IPv4 地址可以用 32 位数据表示,因此可以表示为 long。 IPv6 地址由 128 位数据组成,如果试图将其表示为 long 值,则会带来问题。

在 2.0 框架中,IPAddress 对象有一个 Equal() 方法来确定两个 IPAddress 对象是否相同,但没有内置方法来确定不相等的两个地址的相对位置。 在寻找现有的可用解决方案时,我能找到的唯一解决方案是使用文本比较来确定两个 IP 地址的相对值。 我创建了一个解决方案,该方案不使用文本比较,而是使用现有方法并扩展现有的 IPAddress 对象。

解决方案

可以继承 IPAddress 对象以扩展功能。 本文介绍了向基本对象添加功能的基本方法,以确定两个地址的相对位置并确定一个地址是否在给定范围内。 这些功能将同时支持 IPv4 和 IPv6。

关键概念

2.0 框架的 IPAddress 对象有一个名为 GetAddressBytes() 的方法,该方法返回存储地址的 byte 数组表示形式。 对于 IPv4,此 byte 数组的长度 = 4; 对于 IPv6,数组长度 = 16。 给定两个地址,通过比较每对字节的相对值,可以轻松确定两个 IP 地址的相对位置。

不支持比较来自不同地址系列的两个地址。 无法确定 IPv4 地址是高于还是低于 IPv6 地址。

ComparibleIPAddress

派生对象将被称为 ComparibleIPAddress。 它应该继承自 System.Net.IPAddress

构造函数

您必须为继承对象指定一个构造函数。 所有构造函数必须做的只是调用基对象的构造函数。 这是必要的,因为在这种情况下,基对象没有无参数构造函数。

为了保持一致性,我包含了一个构造函数来镜像基对象中的每个可用构造函数。

public ComparibleIPAddress(byte[] address)
    : base(address)
{
    // must override this constructor to enable build //    
}

public ComparibleIPAddress(Int64 address)
    : base(address)
{
    // must override this constructor to enable
    // build / compatibility with base class constructors
}

public ComparibleIPAddress(byte[] address, Int64 scopeid)
    : base(address, scopeid)
{
    // must override this constructor to enable
    // build / compatibility with base class constructors
}

CompareTo 函数

此函数旨在允许我们将当前 IP 地址与给定值进行比较并确定它们相对位置。 如果当前 IP 地址和传递的地址不在同一地址系列中,则该函数将抛出 ArgumentOutOfRangeException

每个地址都将转换为 byte 数组。

两个 byte 数组中的每一对都相互比较。 如果它们不相等,则确定它们的相对值并完成处理。

public int CompareTo(ComparibleIPAddress value)
{
    int returnVal = 0;
    if (this.AddressFamily == value.AddressFamily)
    {
        byte[] b1 = this.GetAddressBytes();
        byte[] b2 = value.GetAddressBytes();

        for (int i = 0; i < b1.Length; i++)
        {
            if (b1[i] < b2[i])
            {
                returnVal = -1;
                break;
            }
            else if (b1[i] > b2[i])
            {
                returnVal = 1;
                break;
            }
        }
    }
    else
    {
        throw new ArgumentOutOfRangeException("value", 
              "Cannot compare two addresses no in the same Address Family.");
    }

    return returnVal;
}

IsInRange 函数

这是 CompareTo 函数的扩展。 一旦我们能够确定两个地址的相对位置,就可以很容易地确定给定地址是否在地址范围内。

此函数检查所有地址是否在同一地址系列中。 同样,如果不是,则会抛出 ArgumentOutOfRangeException

public bool IsInRange(ComparibleIPAddress rangeStartAddress, 
                      ComparibleIPAddress rangeEndAddress)
{
    bool returnVal = false;
    // ensure that all addresses are of the same type otherwise reject //
    if (rangeStartAddress.AddressFamily != rangeEndAddress.AddressFamily)
    {
        throw new ArgumentOutOfRangeException("rangeStartAddress",
        String.Format("The Start Range type {0} and End Range type {1}" + 
                      " are not compatible ip address families.", 
                      rangeStartAddress.AddressFamily.ToString(), 
                      rangeEndAddress.AddressFamily.ToString()));
    }

    if (rangeStartAddress.AddressFamily == this.AddressFamily)
    {
        returnVal = (CompareTo(rangeStartAddress) >= 0 
                       && CompareTo(rangeEndAddress) <= 0);   
        // no need to check for -2 value as this
        // check has already been undertaken to get into this block //
    }
    else
    {
        throw new ArgumentOutOfRangeException("rangeStartAddress", 
            String.Format("The range type {0} and current value type {1}" + 
                          " are not compatible ip address families", 
                          rangeStartAddress.AddressFamily.ToString(), 
                          this.AddressFamily.ToString()));
    }

    return returnVal;

}

摘要

可以轻松创建派生类以为 IP 地址提供附加功能。

© . All rights reserved.