IP地址与UInt之间不得不说的故事
2012-10-31 16:30
232 查看
IP地址有很多种表示方式,比如原始的二进制,常用的点分十进制。但在涉及到一些有关IP的计算时,这两种表示方式的操作都不是很方便。本文介绍最近在网管项目中使用的uint型ip表示法。使用这种方式,不论是在IP地址的存储,还是计算处理上,都能得到立竿见影的效果。
首先贴出将IP转型为uint的代码:
在上面的GetLongFromIP方法中,首先进行了简单的IP验证,然后将IP地址拆分成byte型的4段。循环中的关键代码 result += (ipUintArr[i] << (24 - i * 8)) 对IP地址的4段分别进行移位操作,再将结果相加。
我们知道,IP地址的最大值表示为:255.255.255.255,也就是其二进制表示的32位全为1。该最大值用上述方法处理后的结果为:4294967295。这正好是C#中uint值的最大值(C#中uint为32位无符号整数)。可以看到,用这种方式将IP地址转换为uint是再合适不过。
理解了上述代码,再将uint格式的IP转换为常见的点分十进制格式,就很简单了,基本上就是上述方法的逆运算:
掌握了IP地址与UInt格式的互转,会给我们在IP地址的处理上带来很多方便。比如常见的某一个网段之间的IP数量(这里的网段用开始IP和结束IP标识):
再比如获取两个IP之间包含的IP地址列表:
另外,如果要查询一个IP地址是否属于某个网段,转换成UInt格式以后非常方便。而传统的Sql不会智能到可以判断 begin_ip<='xxx.xxx.xxx.xxx'<=end_ip。当然,也可以利用一些Sql内置函数实现此功能,只是相比本文提到的UInt方式,相对繁琐:
首先贴出将IP转型为uint的代码:
/// <summary> /// 将点分十进制格式的IP转换为UInt格式 /// </summary> /// <param name="ipStr">IP的点分十进制表示</param> /// <returns></returns> private uint GetUIntFromIP(string ipStr) { if (String.IsNullOrEmpty(ipStr) || !IsIPAddress(ipStr)) return 0; string[] ipArr = ipStr.Split('.'); List<byte> ipIntArr = new List<byte>(); foreach (var s in ipArr) { ipIntArr.Add(byte.Parse(s)); } uint result = 0; for (int i = 0; i < 4; i++) { result += (uint)(ipIntArr[i] << (24 - i * 8)); } return result; } /// <summary> /// 验证是否是正确的IP地址 /// </summary> /// <param name="ipStr">IP字符串</param> /// <returns></returns> private bool IsIPAddress(string IpStr) { if (String.IsNullOrEmpty(IpStr)) return false; Regex regText = new Regex(@"^((1?\d?\d|(2([0-4]\d|5[0-5])))\.){3}(1?\d?\d|(2([0-4]\d|5[0-5])))$"); return regText.IsMatch(IpStr); }
在上面的GetLongFromIP方法中,首先进行了简单的IP验证,然后将IP地址拆分成byte型的4段。循环中的关键代码 result += (ipUintArr[i] << (24 - i * 8)) 对IP地址的4段分别进行移位操作,再将结果相加。
我们知道,IP地址的最大值表示为:255.255.255.255,也就是其二进制表示的32位全为1。该最大值用上述方法处理后的结果为:4294967295。这正好是C#中uint值的最大值(C#中uint为32位无符号整数)。可以看到,用这种方式将IP地址转换为uint是再合适不过。
理解了上述代码,再将uint格式的IP转换为常见的点分十进制格式,就很简单了,基本上就是上述方法的逆运算:
/// <summary> /// 将UInt格式的IP转换为点分十进制格式 /// </summary> /// <param name="ip"></param> /// <returns></returns> private string GetIPStrFromUint(uint ip) { byte first = (byte)(ip >> 24); byte second = (byte)((ip - (first << 24)) >> 16); byte third = (byte)((ip - (second << 16) - (first << 24)) >> 8); byte four = (byte)(ip - (second << 16) - (first << 24) - (third << 8)); return String.Format("{0}.{1}.{2}.{3}", first, second, third, four); }
掌握了IP地址与UInt格式的互转,会给我们在IP地址的处理上带来很多方便。比如常见的某一个网段之间的IP数量(这里的网段用开始IP和结束IP标识):
/// <summary> /// 获取网段之间的IP数量 /// </summary> /// <param name="beginIP"></param> /// <param name="endIP"></param> /// <returns></returns> private uint GetIPCountFromNet(string beginIP,string endIP) { if (String.IsNullOrEmpty(beginIP) || String.IsNullOrEmpty(endIP)) return 0; return GetUIntFromIP(endIP) - GetUIntFromIP(beginIP) + 1; }
再比如获取两个IP之间包含的IP地址列表:
/// <summary> /// 获取两个IP之间的IP列表 /// </summary> /// <param name="beginIP"></param> /// <param name="lastIP"></param> /// <returns></returns> private IEnumerable<string> GetIPListFromNet(string beginIP, string lastIP) { if (String.IsNullOrEmpty(beginIP) || String.IsNullOrEmpty(lastIP)) yield return null; uint beginAddress = GetUIntFromIP(beginIP); uint lastAddress = GetUIntFromIP(lastIP); uint temp = lastAddress - beginAddress; for (uint i = 0; i <= temp; i++) { uint tempAddress = beginAddress + i; //将UInt格式的IP转换为点分十进制表示 string ipAddress = GetIPStrFromUint(tempAddress); yield return ipAddress; } }
另外,如果要查询一个IP地址是否属于某个网段,转换成UInt格式以后非常方便。而传统的Sql不会智能到可以判断 begin_ip<='xxx.xxx.xxx.xxx'<=end_ip。当然,也可以利用一些Sql内置函数实现此功能,只是相比本文提到的UInt方式,相对繁琐:
select count(id) from ip_net where right('000' + parsename('xxx.xxx.xxx.xxx',4),3) + right('000' + parsename('xxx.xxx.xxx.xxx',3),3) + right('000' + parsename('xxx.xxx.xxx.xxx',2),3) + right('000' + parsename('xxx.xxx.xxx.xxx',1),3) between right('000' + parsename(begin_ip,4),3) + right('000' + parsename(begin_ip,3),3) + right('000' + parsename(begin_ip,2),3) + right('000' + parsename(begin_ip,1),3) and right('000' + parsename(end_ip,4),3) + right('000' + parsename(end_ip,3),3) + right('000' + parsename(end_ip,2),3) + right('000' + parsename(end_ip,1),3)
相关文章推荐
- C#的插件编程: 唐伯虎与他八个老婆之间不得不说的故事
- 少妇、伟哥与猪之间不得不说的经济故事
- 问题 F: 小明与隔壁老王之间不得不说的故事
- int,float,double之间不得不说的故事
- 问题 F: 小明与隔壁老王之间不得不说的故事
- int, float, double之间不得不说的故事
- int, float, double之间不得不说的故事
- 1006 小明与隔壁老王之间不得不说的故事(简单)
- int, float, double之间不得不说的故事
- int, float, double之间不得不说的故事
- IP地址和数字之间转化的算法
- Matlab使用笔记-uint8类型之间的运算的坑
- java IP地址与数字之间的转换
- ArcGIS和Hadoop之间的故事之一
- 那些年,乔布斯与拟物化设计之间不为人知的故事!
- Handler,Message,MessageQuene三者不得不说的故事
- C# IP地址与整数之间的转换
- 关于Win7 兼容性不得不说的故事
- 我与尿常规不得不说的故事(一):尿常规检验报告单
- 我和DELPHI不得不说的故事之-------数据库(上)