摘要
大概就是比如我给出一个ip范围 192.168.1.66-192.168.1.90,怎么快速算出合适的网络192.168.1.64/27,也就是 192.168.1.64->192.168.1.95
1、口算
- 网络:192.168.1.66,66最近的2的次方数64
- IP数:192.168.1.90-192.168.1.66=24
- IP数:24+1=25,比25大的2的次方数,2^5=32
- 掩码:32-5=27
- 结果:192.168.1.64/27
2、代码
using System.Buffers.Binary;
using System.Net;
using System.Numerics;
namespace StunNATDetector
{
class Program
{
static async Task Main(string[] args)
{
//主网络掩码
byte mainPrefixLength = 24;
uint mainPrefixValue = mainPrefixLength < 1 ? 0 : 0xffffffff << (32 - mainPrefixLength);
//按范围找到最接近的子网段
uint startIpValue = BinaryPrimitives.ReadUInt32BigEndian(IPAddress.Parse("192.168.0.66").GetAddressBytes());
uint endIpValue = BinaryPrimitives.ReadUInt32BigEndian(IPAddress.Parse("192.168.0.90").GetAddressBytes());
//开始 66
uint originStart = startIpValue & ~mainPrefixValue;
//结束 90
uint originEnd = endIpValue & ~mainPrefixValue;
//开始最近二次幂数 64
uint start = FindNearestPowerOfTwo(originStart);
//掩码26
byte prefixLength = (byte)(32 - (int)Math.Log2(FindNearestPowerOfTwo(originEnd - start + 1 )));
uint prefixLengthValue = prefixLength < 1 ? 0 : 0xffffffff << (32 - prefixLength);
//网络号 192.168.0.64
uint networkValue = (startIpValue & prefixLengthValue) | start;
IPAddress networkIp = new IPAddress(BinaryPrimitives.ReverseEndianness(networkValue));
//广播号 192.168.0.95
uint broadcastValue = startIpValue | ~prefixLengthValue;
IPAddress broadcastIp = new IPAddress(BinaryPrimitives.ReverseEndianness(broadcastValue));
Console.WriteLine($"{networkIp}/{prefixLength},{networkIp}->{broadcastIp}");
}
/// <summary>
/// 最近的二次幂数
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static uint FindNearestPowerOfTwo(uint number)
{
if (number <= 1)
{
return 1;
}
// 31 - 左边1之前的全0个数 = 最后一个1的位置
// 66 01100000 -> 6 1<<6=64 和 1<<7=128
int highestBit = 31 - BitOperations.LeadingZeroCount(number);
uint lower = 1U << highestBit;
uint upper = 1U << (highestBit + 1);
return (number - lower <= upper - number) ? lower : upper;
}
}
}