高性能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. easyUI中的form表单

    首先创建form表单,并在form表单上创建id便于执行表单验证 <form id="form1"action="" method="post& ...

  2. 使用JS实现图片展示瀑布流效果

    不知大家有没有发现,一般的图片展示网站都会使用瀑布流效果,所谓的瀑布流 就是网站内的图片不会一下子全缓存出来,而是等你滚动到一定的距离的时候, 下面的图片才会继续缓存,并且图片也是随机出现的,只是宽度 ...

  3. FAT32文件系统

  4. 实战Java虚拟机之三“G1的新生代GC”

    今天开始实战Java虚拟机之三:“G1的新生代GC”. 总计有5个系列 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实 ...

  5. ArithUtil工具类 : 精确计算各种运算

    package com.autoserve.mh.common.util;   import java.math.BigDecimal; import java.text.DecimalFormat; ...

  6. Unity字节序问题

    问题 Unity中有些配置信息并不想在发布之后给其他人看到,所以在打包的时候进行了简单的编码处理,然后保存为.bytes类型,读取的时候再进行解码处理.今天遇到的很奇葩的问题是: 如果bytes文件U ...

  7. Unity透明材质Batch

    NO Batch  ? 游戏场景中存在大量例子的时候,DrallCall的压力很大,但是遍历一遍之后发现,为啥一样的粒子特效竟然没有合并,why?经过很多测试后发现,如果把透明材质的修改为非半透明的, ...

  8. 百度编辑器ueditor 的 submit 表单提交

    页面中表单提交代码: <input type="submit" name="Submit" value="修改保存"> 提交的结 ...

  9. 如何使用Google Map API开发Android地图应用

    两年前开发过的GoogleMap已经大变样,最近有项目要用到GoogleMap,重新来配置Android GoogleMap开发环境,还真是踩了不少坑. 一.下载Android SDK Manager ...

  10. java beans

    There are N little kids sitting in a circle, each of them are carrying some java beans in their hand ...