最新一代文件结构 超高性能解析IP数据库 qqzeng-ip.dat

时间:2023-02-12 07:44:30

高性能IP数据库格式 qqzeng-ip.dat

编码:UTF8           字节序:Little-Endian

返回多个字段信息(如:亚洲|中国|香港|九龙|油尖旺|新世界电讯|810200|*|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

最新一代文件结构 超高性能解析IP数据库 qqzeng-ip.dat

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|*|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|*|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数据库&lpar;qqwry&period;dat&rpar;转换成最新的IP数据库格式&lpar;ipwry&period;dat&rpar;

    纯真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&period;NET】利用纯真IP数据库查询IP地址及信息

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

  4. 优化读取纯真IP数据库QQWry&period;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&period;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. PowerDesigner 正向工程 和 逆向工程 说明

    PowerDesigner 正向工程 和 逆向工程 说明 database数据库脚本oraclegenerationsql   目录(?)[+]   一. 正向工程与逆向工程说明 在前面几篇里介绍了几 ...

  2. iOS8学习笔记2--autolayout

    iOS支持的设备如今已经具有了很多的尺寸,针对这些不同的尺寸每一个都做一个独立的APP肯定是不现实的,于是苹果在iOS8之后推出了autolayout和sizeclass,同时还有VFL界面设计语言 ...

  3. WebGIS开源解决方案之矢量数据导入

    前几篇介绍了开源WebGIS开发环境的搭建,本篇开始陆续介绍这些软件的使用,WebGIS的开发,首要的问题是解决数据来源,本篇主要介绍矢量数据在开源空间数据库PostgreSQL中的存储.后续篇幅中再 ...

  4. tensorflow 训练之tensorboard使用

    1.add saclar and histogram tf.summary.scalar('mean', mean) tf.summary.histogram('histogram', var) 2. ...

  5. IIS 接口访问404

    IIS->网站->ASP->启用父路径(true)

  6. 使用VMware通过vmdk文件创建XP虚拟机

    一.打开VMware workstation10,转到主页,选择“创建新的虚拟机”,然后选择“自定义(高级)”选项 二.虚拟机硬件兼容性选择默认兼容10.0模式,下一步之后,选择“稍后安装操作系统” ...

  7. 在C&num;中,Json的序列化和反序列化的几种方式总结 转载

    转载自  https://www.cnblogs.com/caofangsheng/p/5687994.html    谢谢 在这篇文章中,我们将会学到如何使用C#,来序列化对象成为Json格式的数据 ...

  8. LG1337 &lbrack;JSOI2004&rsqb;平衡点 &sol; 吊打XXX

    题意 题目描述 如图:有n个重物,每个重物系在一条足够长的绳子上.每条绳子自上而下穿过桌面上的洞,然后系在一起.图中X处就是公共的绳结.假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不 ...

  9. Ruby 集合数组常用遍历方法

    迭代器简介 先简单介绍一下迭代器. 1.一个Ruby迭代器就是一个简单的能接收代码块的方法(比如each这个方法就是一个迭代器).特征:如果一个方法里包含了yield调用,那这个方法肯定是迭代器: 2 ...

  10. spring-session使用配置(分布式共享session配置)

    1. 添加依赖 <dependency> <groupId>org.springframework.session</groupId> <artifactId ...