高性能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的更多相关文章

  1. 纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)

    纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat) 转载自:http://blog.cafeboy.org/2011/02/25/qqwry-to-ipwry/ ht ...

  2. python3通过纯真IP数据库查询IP归属地信息

    在网上看到的别人写的python2的代码,修改成了python3. 把纯真IP数据库文件qqwry.dat放到czip.py同一目录下. #! /usr/bin/env python # -*- co ...

  3. 【VB.NET】利用纯真IP数据库查询IP地址及信息

    几年前从某个博客抄来的,已经忘记原地址了,如果需要C#版的,可以在博客园搜到吧.我因为自己用,所以转换为了VBNET代码,而且也放置了很久,今天无意间翻出来,就分享给大家吧. 首先,先下载 纯真数据库 ...

  4. 优化读取纯真IP数据库QQWry.dat获取地区信息

    改自HeDaode 2007-12-28的代码 将之改为从硬盘读取后文件后,将MemoryStream放到内存中,提高后续查询速度 ///<summary> /// 提供从纯真IP数据库搜 ...

  5. IP数据库

    免费的IP数据库,qqwry.dat文件:通过读文件来获取ip地址的地区信息: QQWry.Dat的格式如下: +----------+| 文件头 | (8字节)+----------+| 记录区 | ...

  6. 最新IP数据库 存储优化 查询性能优化 每秒解析上千万

    高性能IP数据库格式详解 每秒解析1000多万ip  qqzeng-ip-ultimate.dat 3.0版 编码:UTF8     字节序:Little-Endian 返回规范字段(如:亚洲|中国| ...

  7. 纯真IP数据库解析Delphi D10.1下正常使用

    直接一个单元,代码分享出来. unit   Net.IPLocation; interface uses System.Classes, System.SysUtils, Winapi.WinSock ...

  8. OpenStack最新版本Folsom架构解析

    OpenStack最新版本Folsom架构解析摘要:OpenStack的第6版,版本代号为Folsom的最新版于今年九月底正式发布,Folsom将支持下一代软件定义网络(SDN)作为其核心组成部分.F ...

  9. 数据采集:完美下载淘宝Ip数据库 简单的程序节省60元人民币而不必购买数据库

    曾经做网站类型的程序时,经常需要收集客户端的访问数据,然后加以分析.这需要一个Ip数据库,数据表中显示Ip所在的省份市区等信息.网络上有流传的Ip纯真数据库,一些公开的Web服务也可以查询Ip地址信息 ...

随机推荐

  1. python字符串

    字符串格式化 字符串格式化使用字符串格式化操作符%来实现:格式化字符串 % 值(字符串或者数字或者多个值的元组,字典) >>> format = "hello, %s. % ...

  2. svn: E155004 is already locked 解决方案

    在出错文件夹下(或整个工程项目),鼠标右键TortoiseSVN->Clean up. SVN错误:Attempted to lock an already-locked dir 1.出现这个问 ...

  3. 修改ie的默认值 为ie10

    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10" />

  4. java 4种方式读取配置文件 + 修改配置文件

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 方式一采用ServletContext读取读取配置文件的realpath然后通过文件流读取出来 方式二采用ResourceB ...

  5. 从程序员到CTO的Java技术路线图(我爱分享)

    在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平. Java程序员 高级特性 反射.泛型. ...

  6. app活动页面上的痛点

    app项目上需要做一个小的活动,先看下页面布局 需求是这5个板块逐个展示,展示一块的时候,页面整体向上滚动一定的距离. 刚开始考虑的时候,是准备依赖css3属性的transition实现的,包括顺序延 ...

  7. 基于ssh框架开发的购物系统的质量属性

    根据前面的博客,我们已经大致了解了ssh架构开发整体概念:Struts是一个实现了MVC模式的经典的框架:Hibernate是轻量级Java EE应用的持久层解决方案,以面向对象的方式提供了持久化类到 ...

  8. QHash

    #include <QCoreApplication> #include<QHash> #include<QDebug> int main(int argc, ch ...

  9. Java读写资源文件类Properties

    Java中读写资源文件最重要的类是Properties 1) 资源文件要求如下: 1.properties文件是一个文本文件 2.properties文件的语法有两种,一种是注释,一种属性配置.  注 ...

  10. java中一个查询业务的流程

    因为有用到分页,首先建一个page类 1 public class Page<T> { 2 private int pageSize; //每页显示条数 3 private int cur ...