通过子网掩码计算IP范围

8
如果我有一个子网掩码,例如255.255.255.0和一个IP地址192.168.1.5,有没有一种简单的方法来确定此子网中所有可能的IP地址?
在这种情况下:
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
...
...
192.168.1.252
192.168.1.253
192.168.1.254
192.168.1.255

到目前为止我找到的都是过于笨重的.net库,难道没有使用默认命名空间来解决此问题的本地方法吗?


很抱歉,没有内置的方法。你要么自己进行数学/位移操作,要么使用第三方工具。 - Lloyd
当然。为此,您需要了解子网掩码和C#的基本二进制运算符。您对此进行了研究吗? - zerkms
AND和位移,话不多说。 - drum
你是想列出所有地址,还是只是确定特定地址是否在子网中?例如,一个 255.0.0.0 的子网掩码将包含 16,777,216 个地址。 - mellamokb
@zerkms 我本来希望有内置的方法,但看起来我得自己动手了。 :/ - Neurodefekt
显示剩余3条评论
5个回答

13

十分钟代码,未完全测试:

class IPSegment {

    private UInt32 _ip;
    private UInt32 _mask;

    public IPSegment(string ip, string mask) {
        _ip = ip.ParseIp();
        _mask = mask.ParseIp();
    }

    public UInt32 NumberOfHosts {
        get { return ~_mask+1; }
    }

    public UInt32 NetworkAddress {
        get { return _ip & _mask; }
    }

    public UInt32 BroadcastAddress {
        get { return NetworkAddress + ~_mask; }
    }

    public IEnumerable<UInt32> Hosts(){
        for (var host = NetworkAddress+1; host < BroadcastAddress; host++) {
            yield return  host;
        }
    }

}

public static class IpHelpers {
    public static string ToIpString(this UInt32 value) {
        var bitmask = 0xff000000;
        var parts = new string[4];
        for (var i = 0; i < 4; i++) {
            var masked = (value & bitmask) >> ((3-i)*8);
            bitmask >>= 8;
            parts[i] = masked.ToString(CultureInfo.InvariantCulture);
        }
        return String.Join(".", parts);
    }

    public static UInt32 ParseIp(this string ipAddress) {
        var splitted = ipAddress.Split('.');
        UInt32 ip = 0;
        for (var i = 0; i < 4; i++) {
            ip = (ip << 8) + UInt32.Parse(splitted[i]);
        }
        return ip;
    }
}

使用方法:

    static void Main(string[] args) {

        IPSegment ip = new IPSegment("192.168.1.1","255.255.255.248");

        Console.WriteLine(ip.NumberOfHosts);
        Console.WriteLine(ip.NetworkAddress.ToIpString());
        Console.WriteLine(ip.BroadcastAddress.ToIpString());

        Console.WriteLine("===");
        foreach (var host in ip.Hosts()) {
            Console.WriteLine(host.ToIpString());
        }
        Console.ReadLine();

    }

9
为了确定地址范围,请按照以下步骤进行:
1)获取您的子网掩码(这里是255.255.255.0)并将其转换为二进制:

11111111.11111111.11111111.00000000

11111111.11111111.11111111.00000000

 (  8    +    8   +   8    +    0    = 24 ->  So you can write your ip adresse like this : 192.168.1.x/24 because you are in a /24 network)

2) 在一个/24网络中,你有256-2=254个可用的IP地址用于主机(其中一个是网络地址(范围内的第一个),另一个是广播地址(范围内的最后一个))。

3) 要获取你的范围,只需获取你的网络地址(根据子网掩码确定的第一个IP地址)并获取接下来的255个IP地址,你就可以得到你的范围。

你的网络地址:

在二进制中,最后一个八位必须为零:

xxxxxxxx.xxxxxxxx.xxxxxxxx.00000000

你的广播地址:

二进制中,最后一个八位字节必须等于1:

xxxxxxxx.xxxxxxxx.xxxxxxxx.11111111

您的IP地址是192.168.1.5。 转换成二进制为:

11000000.10101000.00000000.00000101
  1. 你的网络地址: 11000000.10101000.00000000.00000000 <-> 192.168.1.0
  2. 你的广播地址: 11000000.10101000.00000000.11111111 <-> 192.168.1.255
  3. 可用的第一个 IP 地址: 192.168.1.1

  4. 可用的最后一个 IP 地址: 192.168.1.254

希望您喜欢阅读这篇翻译。 如果您有任何问题,请告诉我, Loris


如果有人需要第一步的代码:var bytes = subnetMask.GetAddressBytes(); var binarySubnetMask = String.Join(".", bytes.Select(b => Convert.ToString(b, 2).PadLeft(8, '0'))); int mask = binarySubnetMask.Count(b => b == '1'); - Brett

1

使用方法:

string[] range GetIpRange("100.68.18.218", "255.255.255.252",true)`;

最后一个参数 true 是过滤第一个和最后一个 IP
如果要获取完整的答案,请将其设置为 false

它将返回第一个和最后一个可用的 IP。

以下是所有带有解释的代码:


/// <summary>
/// IPAddress to UInteger 
/// </summary>
/// <param name="ipAddress"></param>
/// <returns></returns>
public static uint IPToUInt(this string ipAddress)
{
    if (string.IsNullOrEmpty(ipAddress))
        return 0;

    if (IPAddress.TryParse(ipAddress, out IPAddress ip))
    {
        var bytes = ip.GetAddressBytes();
        Array.Reverse(bytes);
        return BitConverter.ToUInt32(bytes, 0);
    }
    else
        return 0;

}

/// <summary>
/// IP in Uinteger to string
/// </summary>
/// <param name="ipUInt"></param>
/// <returns></returns>
public static string IPToString(this uint ipUInt)
{
    return ToIPAddress(ipUInt).ToString();
}


/// <summary>
/// IP in Uinteger to IPAddress
/// </summary>
/// <param name="ipUInt"></param>
/// <returns></returns>
public static IPAddress ToIPAddress(this uint ipUInt)
{
    var bytes = BitConverter.GetBytes(ipUInt);
    Array.Reverse(bytes);
    return new IPAddress(bytes);
}

/// <summary>
/// First and Last IPv4 from IP + Mask
/// </summary>
/// <param name="ipv4"></param>
/// <param name="mask">Accepts CIDR or IP. Example 255.255.255.0 or 24</param>
/// <param name="filterUsable">Removes not usable IPs from Range</param>
/// <returns></returns>
/// <remarks>
/// If ´filterUsable=false´ first IP is not usable and last is reserved for broadcast.
/// </remarks>
public static string[] GetIpRange(string ipv4, string mask, bool filterUsable)
{
    uint[] uiIpRange = GetIpUintRange(ipv4, mask, filterUsable);

    return Array.ConvertAll(uiIpRange, x => IPToString(x));
}

/// <summary>
/// First and Last IPv4 + Mask. 
/// </summary>
/// <param name="ipv4"></param>
/// <param name="mask">Accepts CIDR or IP. Example 255.255.255.0 or 24</param>
/// <param name="filterUsable">Removes not usable IPs from Range</param>
/// <returns></returns>
/// <remarks>
/// First IP is not usable and last is reserverd for broadcast.
/// Can use all IPs in between
/// </remarks>
public static uint[] GetIpUintRange(string ipv4, string mask, bool filterUsable)
{
    uint sub;
    //check if mask is CIDR Notation
    if (mask.Contains(".")) {
        sub = IPToUInt(mask);
    }
    else
    {
        sub = ~(0xffffffff >> Convert.ToInt32(mask));
    }

    uint ip2 = IPToUInt(ipv4);
 

    uint first = ip2 & sub;
    uint last = first | (0xffffffff & ~sub);

    if (filterUsable)
    {
        first += 1;
        last -= 1; 
    }

    return new uint[] { first, last };
}


1

是的,将所有内容转换为32位表示(假设为IPv4)。如果您的掩码为M,IP地址为IP,则IP范围为(M&IP)+1,(M&IP)+2,...,(M&IP)+(~M)-1。其中&是按位与,~是按位非。

要将事物转换为32位表示,IP地址a.b.c.d中的每个位置都是一个8位数字。


0

很好的选择。不要为此使用额外的库。这很简单。这是我做的方式:

public static uint[] GetIpRange(string ip, IPAddress subnet)
{
    uint ip2 = Utils.IPv4ToUInt(ip);
    uint sub = Utils.IPv4ToUInt(subnet);

    uint first = ip2 & sub;
    uint last = first | (0xffffffff & ~sub);

    return new uint[] { first, last };
}

注意:
您需要进行一些额外的工作,将IP转换为uint并返回(应该很容易)。然后,您可以使用简单的for循环在firstlast之间迭代所有IP。

类似于以下内容(未经测试):

byte[] bytes = subnet.GetAddressBytes();
uint sub = (uint)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);

IPAddress ip1 = IPAddress.Parse(ip);
bytes = ip1.GetAddressBytes();
uint ip2 = (uint)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);

你能提供一个简单的ip2/sub IP地址和相应的uint等效值来评估我们的工作吗? - Maslow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接