最新一代文件结构 超高性能解析IP数据库 qqzeng-ip.dat
高性能IP数据库格式 qqzeng-ip.dat
编码:UTF8 字节序:Little-Endian
返回多个字段信息(如:亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|Hong Kong|HK|114.17495|22.327115)
------------------------ 文件结构 ---------------------------
//文件头 16字节(4-4-4-4)
[索引区第一条流位置][索引区最后一条流位置][前缀区第一条的流位置][前缀区最后一条的流位置]
//内容区 长度无限制
[地区信息][地区信息]……唯一不重复
//索引区 12字节(4-4-3-1)
[起始IP][结束IP][地区流位置][流长度]
//前缀区 9字节(1-4-4)
[0-255][索引区start索引][索引区end索引]
------------------------ 文件结构 ---------------------------
优势:索引区分为[起始IP][结束IP][地区偏移][长度],减少多级偏移跳转步骤和长度的解析,提高效率;
根据ip第一位字节作为前缀,解析出以这个数字为前缀的第一个索引和最后一个索引,缩小查询区间,
然后在这区间再用二分查找快速查找到对应区间,效率提高几个等级
压缩:原版txt为15M,生成这种dat结构为2.45M
性能:每秒解析300多万
对比:相比其他dat更简洁更高效
创建:qqzeng-ip 于 2015-08-01
代码:https://github.com/zengzhan/qqzeng-ip
public class IPSearch
{
private Dictionary<uint, PrefixIndex> prefixDict;
private byte[] indexBuffer;
private byte[] data;
long firstStartIpOffset;//索引区第一条流位置
long lastStartIpOffset;//索引区最后一条流位置
long prefixStartOffset;//前缀区第一条的流位置
long prefixEndOffset;//前缀区最后一条的流位置
long ipCount; //ip段数量
long prefixCount; //前缀数量 /// <summary>
/// 初始化二进制dat数据
/// </summary>
/// <param name="dataPath"></param>
public IPSearch(string dataPath)
{
using (FileStream fs = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
data = new byte[fs.Length];
fs.Read(data, , data.Length);
} firstStartIpOffset = BytesToLong(data[], data[], data[], data[]);
lastStartIpOffset = BytesToLong(data[], data[], data[], data[]);
prefixStartOffset = BytesToLong(data[], data[], data[], data[]);
prefixEndOffset = BytesToLong(data[], data[], data[], data[]); //prefixCount 不固定为256 方便以后自由定制 国内版 国外版 全球版 或者某部分 都可以 ipCount = (lastStartIpOffset - firstStartIpOffset) / + ; //索引区块每组 12字节
prefixCount = (prefixEndOffset - prefixStartOffset) / + ; //前缀区块每组 9字节 //初始化前缀对应索引区区间
indexBuffer = new byte[prefixCount * ];
Array.Copy(data, prefixStartOffset, indexBuffer, , prefixCount * );
prefixDict = new Dictionary<uint, PrefixIndex>();
for (var k = ; k < prefixCount; k++)
{
int i = k * ;
uint prefix = (uint)indexBuffer[i];
long start_index = BytesToLong(indexBuffer[i + ], indexBuffer[i + ], indexBuffer[i + ], indexBuffer[i + ]);
long end_index = BytesToLong(indexBuffer[i + ], indexBuffer[i + ], indexBuffer[i + ], indexBuffer[i + ]);
prefixDict.Add(prefix, new PrefixIndex() { prefix = prefix, start_index = start_index, end_index = end_index });
} } public static uint IpToInt(string ip,out uint prefix)
{
byte[] bytes = IPAddress.Parse(ip).GetAddressBytes();
prefix = (uint)bytes[];
return (uint)bytes[] + (((uint)bytes[]) << ) + (((uint)bytes[]) << ) + (((uint)bytes[]) << );
} public static string IntToIP(uint ip_Int)
{
return new IPAddress(ip_Int).ToString();
} /// <summary>
/// 根据ip查询多维字段信息
/// </summary>
/// <param name="ip">ip地址(123.4.5.6)</param>
/// <returns>亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|Hong Kong|HK|114.17495|22.327115</returns>
public string Query(string ip)
{
uint ip_prefix_value;
uint intIP = IpToInt(ip,out ip_prefix_value);
uint high = ;
uint low = ;
uint startIp = ;
uint endIp = ;
uint local_offset = ;
uint local_length = ; if (prefixDict.ContainsKey(ip_prefix_value))
{
low = (uint)prefixDict[ip_prefix_value].start_index;
high = (uint)prefixDict[ip_prefix_value].end_index;
}
else
{
return "";
} uint my_index = low == high? low : BinarySearch(low, high, intIP); GetIndex(my_index, out startIp, out endIp, out local_offset, out local_length); if ((startIp <= intIP) && (endIp >= intIP))
{
return GetLocal(local_offset, local_length);
}
else
{
return "";
} }
/// <summary>
/// 二分逼近算法
/// </summary>
public uint BinarySearch(uint low, uint high, uint k)
{
uint M = ;
while (low <= high )
{
uint mid = (low + high) / ; uint endipNum = GetEndIp(mid);
if (endipNum >= k)
{ M = mid;
if (mid == )
{
break; //防止溢出
}
high = mid - ;
}
else
low = mid + ;
}
return M;
}
/// <summary>
/// 在索引区解析
/// </summary>
/// <param name="left">ip第left个索引</param>
/// <param name="startip">返回开始ip的数值</param>
/// <param name="endip">返回结束ip的数值</param>
/// <param name="local_offset">返回地址信息的流位置</param>
/// <param name="local_length">返回地址信息的流长度</param>
private void GetIndex(uint left, out uint startip, out uint endip, out uint local_offset, out uint local_length)
{
long left_offset = firstStartIpOffset + (left * );
startip = BytesToLong(data[left_offset], data[ + left_offset], data[ + left_offset],data[ + left_offset]);
endip = BytesToLong(data[+left_offset], data[ + left_offset], data[ + left_offset], data[ + left_offset]);
local_offset = (uint)data[ + left_offset] + (((uint)data[ + left_offset]) << ) + (((uint)data[ + left_offset]) << );
local_length = (uint)data[ + left_offset];
}
/// <summary>
/// 只获取结束ip的数值
/// </summary>
/// <param name="left">索引区第left个索引</param>
/// <returns>返回结束ip的数值</returns>
private uint GetEndIp(uint left)
{
long left_offset = firstStartIpOffset + (left * );
return BytesToLong(data[ + left_offset], data[ + left_offset], data[ + left_offset], data[ + left_offset]); } /// <summary>
/// 返回地址信息
/// </summary>
/// <param name="local_offset">地址信息的流位置</param>
/// <param name="local_length">地址信息的流长度</param>
/// <returns></returns>
private string GetLocal(uint local_offset, uint local_length)
{
byte[] buf = new byte[local_length];
Array.Copy(data, local_offset, buf, , local_length);
return Encoding.UTF8.GetString(buf, , (int)local_length); } /// <summary>
/// 字节转整形 小节序
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="d"></param>
/// <returns></returns>
private uint BytesToLong(byte a, byte b, byte c, byte d)
{
return ((uint)a << ) | ((uint)b << ) | ((uint)c << ) | ((uint)d << );
}
} /*
(调用例子):
IPSearch finder = new IPSearch("qqzeng-ip.dat");
string result = finder.Query("1.2.3.4");
--> result="亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|Hong Kong|HK|114.17495|22.327115"
*/ public class PrefixIndex
{
public uint prefix { get; set; }
public long start_index { get; set; }
public long end_index { get; set; }
}
最新一代文件结构 超高性能解析IP数据库 qqzeng-ip.dat的更多相关文章
- 纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)
纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat) 转载自:http://blog.cafeboy.org/2011/02/25/qqwry-to-ipwry/ ht ...
- python3通过纯真IP数据库查询IP归属地信息
在网上看到的别人写的python2的代码,修改成了python3. 把纯真IP数据库文件qqwry.dat放到czip.py同一目录下. #! /usr/bin/env python # -*- co ...
- 【VB.NET】利用纯真IP数据库查询IP地址及信息
几年前从某个博客抄来的,已经忘记原地址了,如果需要C#版的,可以在博客园搜到吧.我因为自己用,所以转换为了VBNET代码,而且也放置了很久,今天无意间翻出来,就分享给大家吧. 首先,先下载 纯真数据库 ...
- 优化读取纯真IP数据库QQWry.dat获取地区信息
改自HeDaode 2007-12-28的代码 将之改为从硬盘读取后文件后,将MemoryStream放到内存中,提高后续查询速度 ///<summary> /// 提供从纯真IP数据库搜 ...
- IP数据库
免费的IP数据库,qqwry.dat文件:通过读文件来获取ip地址的地区信息: QQWry.Dat的格式如下: +----------+| 文件头 | (8字节)+----------+| 记录区 | ...
- 最新IP数据库 存储优化 查询性能优化 每秒解析上千万
高性能IP数据库格式详解 每秒解析1000多万ip qqzeng-ip-ultimate.dat 3.0版 编码:UTF8 字节序:Little-Endian 返回规范字段(如:亚洲|中国| ...
- 纯真IP数据库解析Delphi D10.1下正常使用
直接一个单元,代码分享出来. unit Net.IPLocation; interface uses System.Classes, System.SysUtils, Winapi.WinSock ...
- OpenStack最新版本Folsom架构解析
OpenStack最新版本Folsom架构解析摘要:OpenStack的第6版,版本代号为Folsom的最新版于今年九月底正式发布,Folsom将支持下一代软件定义网络(SDN)作为其核心组成部分.F ...
- 数据采集:完美下载淘宝Ip数据库 简单的程序节省60元人民币而不必购买数据库
曾经做网站类型的程序时,经常需要收集客户端的访问数据,然后加以分析.这需要一个Ip数据库,数据表中显示Ip所在的省份市区等信息.网络上有流传的Ip纯真数据库,一些公开的Web服务也可以查询Ip地址信息 ...
随机推荐
- [LintCode] Majority Number 求众数
Given an array of integers, the majority number is the number that occurs more than half of the size ...
- Odoo中本日、本月、上月过滤器实现方法
<filter string="今日订单" name="today" invisible="0" domain="[('da ...
- apache配置rewrite及.htaccess文件(转载)
今天看到一个哥们的帖子发了个rewrite的帖子,以前也写过一个,配置挺简单的,但当时没注意这个问题,当时没有用到.htaccess文件,在机子上测试了一下,发现确实没法用,于是开始找问题的所在. 自 ...
- 事后分析报告(Postmortem Report)
小组讨论照片 设想和目标 1.我们的团队项目为英语单词学习助手,名为“我爱记单词”.主要提供服务包括:单词查询,单词测试,单词记忆和中英互译.目前开发的是单机版本,用户可以根据自己的需求灵活的使用相应 ...
- Django URL name详解
我们基于上一节的代码来开始这一节的内容. 上节源代码:zqxt_views(django 1.4 - django 1.10).zip [更新于 2016-09-06 00:13:23] 1. 打开 ...
- Spring MVC:在jsp中引入css
为了将css引入jsp中,今天可真是踩了好多坑,最后在stackoverflow上找到了解决方法,不多说贴出代码. 在web.xml中添加以下代码: <servlet-mapping> & ...
- 关于防止App被第三方应用Kill掉的问题
由于一些需求的原因需要让自己App长时间在后台.虽然这样的做法是很Orz的,但是由于项目需求有时候不得不这样做.QQ.微信之所以没被第三方应用直接给kill掉,从市场原因腾讯的软件已经深入人心,很多厂 ...
- 温故而知新 兼容性较强的轮播器superslide.js
官网: http://www.superslide2.com/index.html demo: http://www.superslide2.com/demo.html API: http://www ...
- 如何提高Java并行程序性能??
在Java程序中,多线程几乎已经无处不在.与单线程相比,多线程程序的设计和实现略微困难,但通过多线程,我们却可以获得多核CPU带来的性能飞跃,从这个角度说,多线程是一种值得尝试的技术.那么如何写出高效 ...
- 设计模式之六大原则——接口隔离原则(ISP)
设计模式之六大原则——接口隔离原则(ISP) 转载于:http://www.cnblogs.com/muzongyan/archive/2010/08/04/1792528.html 接口隔离原则 ...