扩展 IPAddress 对象以允许对两个 IP 地址进行相对比较
本文概述了如何扩展 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 地址提供附加功能。