关于IP地址
IP地址的科普这里就简单说明一下,更多详细的知识直接百科吧。
我们知道IPv4地址是由4段0-255的数字组成的,形如:a.b.c.d(0≤a,b,c,d≤255),IPv4也叫32位地址,为什么是32位呢,我们把每一段转换成二进制之后,它的取值范围就是00000000-11111111,所以加起来就是32位。
那IP地址的本质是一个32位的二进制数,我们便可以将这个32位的二进制再转换成十进制,进行比较不就可以了吗?
IP地址转十进制
以4.3.2.1为例,对应的十进制是多少呢?
第一步,转换成二进制,即00000100.00000011.00000010.00000001;
第二步,去掉“.”,得到完整的二进制数:00000100000000110000001000000001;
第三步,再转回十进制:00000100000000110000001000000001(2)=67305985(10);
所以4.3.2.1对应的十进制数是67305985。
那有没有什么更快的办法来计算这个十进制数呢?
肯定是有的,就是移位操作,67305985=4<<24+3<<16+2<<8+1。这样就实现了IP地址转十进制数的操作,即使是128位的IPv6,也是如法炮制!
判断一个IP是否在某个IP段
所以判断一个是否在某个IP段就直接将要对比的IP地址分别转换成十进制比大小就好了,也不用担心什么性能问题,因为移位操作是CPU最擅长做的事情,比起加减乘除还要来得快,因此,我们可以将IP地址转十进制的操作封装为一个方法,方便直接调用:
/// <summary> /// IP地址转换成数字 /// </summary> /// <param name="addr">IP地址</param> /// <returns>数字,输入无效IP地址返回0</returns> private static uint IPToID(string addr) { if (!IPAddress.TryParse(addr, out var ip)) { return 0; } byte[] bInt = ip.GetAddressBytes(); if (BitConverter.IsLittleEndian) { Array.Reverse(bInt); } return BitConverter.ToUInt32(bInt, 0); }
其中ip.GetAddressBytes()这个操作便是IPAddress自带的将IP地址按“.”分割后的数组,BitConverter.ToUInt32便是将一组数字进行移位计算得到结果,所以不需要我们再去手动Split和手动移位计算。
基于上面的方法,我们还能进一步封装一个直接判断IP地址是否在IP段内的方法:
/// <summary> /// 判断IP地址在不在某个IP地址段 /// </summary> /// <param name="input">需要判断的IP地址</param> /// <param name="begin">起始地址</param> /// <param name="ends">结束地址</param> /// <returns></returns> public static bool IpAddressInRange(this string input, string begin, string ends) { uint current = IPToID(input); return current >= IPToID(begin) && current <= IPToID(ends); }
接下来直接测试192.168.2.3是不是在192.168.1.1-192.168.2.255这个网段了,肉眼一看,肯定是在这个地址段内,那看看代码的执行结果吧。
判断一个是否在某个IP段其实就这么简单!
转载于:https://masuit.com/1802