Compare commits

...

47 Commits

Author SHA1 Message Date
lionsoul 74b3045339 Update the ip data to version 2018/03/26 2018-03-27 14:38:33 +08:00
lionsoul 7cb8bc4b9d
Merge pull request #31 from RocherKong/master
add C# support ( from RocherKong)
2018-02-11 11:56:51 +08:00
RocherKong b65d8206ba add support for C# 2018-02-09 22:04:01 +08:00
lionsoul 39555fc266 Update the data to version 2018/01/12 2018-01-16 15:08:30 +08:00
lionsoul 68540b4db4 Fix the doc error 2017-11-23 21:25:32 +08:00
lionsoul 217a7dab9e Untrack the binding/java/target/ directory 2017-10-28 15:38:09 +08:00
lionsoul 07ea5994b8 Update the REAMD 2017-10-23 15:31:46 +08:00
lionsoul 02391e2057 Add the maven repository address 2017-10-23 13:50:57 +08:00
lionsoul 5f29715ec2 java binding maven upload & track the latest dbMaker.jar 2017-10-23 13:48:49 +08:00
lionsoul 4d0ce55008 bold the upgrade notice 2017-10-21 13:10:16 +08:00
lionsoul 29bacb0c8a Update the README 2017-10-21 13:08:26 +08:00
lionsoul a49fae2ce8 Update the README 2017-10-21 13:07:29 +08:00
lionsoul 1f0b07d42b Update the notice 2017-10-21 13:06:08 +08:00
lionsoul b0aecd7046 active the upgrade notice 2017-10-21 13:05:14 +08:00
lionsoul b48dbe5248 Bug fixed: Adjust the super header length to 8192 for all client implementation 2017-10-21 12:47:24 +08:00
Wilson Wang 4ffb1334a1 !4 python 3正常运行
Merge pull request !4 from Wilson Wang/master
2017-10-21 12:13:29 +08:00
wfifi 0f39924b08 add python3 support 2017-10-20 18:09:07 +08:00
lionsoul 7f1216eb6f Merge branch 'master' of http://git.oschina.net/lionsoul/ip2region 2017-10-20 12:13:30 +08:00
lionsoul 6eec7a2c42 Update the to data 2017/10/09 version 2017-10-20 12:13:19 +08:00
lionsoul 499bc1887e Merge pull request #19 from chengpiaopiao/master
fix incorrect python test helper.
2017-09-16 09:39:27 +08:00
chengpiaopiao 1ad6274118 fix incorrect python test helper. 2017-09-15 15:40:04 +08:00
dongyado 769ab315b1 correct post path 2017-09-08 14:10:31 +08:00
lionsoul 979e9bdda7 Merge pull request #15 from mohong122/master
Golang binding 增加控制台实例
2017-08-01 12:18:56 +08:00
mohong e4f54054c4 Merge pull request #1 from lionsoul2014/master
合并远程
2017-05-25 14:51:46 +08:00
lionsoul af9c8794ff Merge branch 'master' of https://github.com/lionsoul2014/ip2region 2017-04-19 10:49:13 +08:00
lionsoul f93b8d2dfb Fix the demo doc error 2017-04-19 10:48:10 +08:00
lionsoul 546be60b0a Merge pull request #11 from zhuangya/jest
chore: test in jest
2017-04-14 13:11:52 +08:00
Ya Zhuang eae269f37d
chore: test in jest 2017-04-14 12:47:55 +08:00
lionsoul 90682e06eb track the latest binary db data 2017-04-10 11:04:02 +08:00
lionsoul 7d4a36d9bc Update the 1.2.4 version desc 2017-04-07 19:04:12 +08:00
lionsoul fe4057d8aa Add the changes for version 1.2.4 2017-04-07 18:53:55 +08:00
lionsoul bd3ffadabf Update the source and the binary ip data to version 2017/03/15 2017-04-07 18:53:29 +08:00
lionsoul b7376d5868 Add the author info for binding/c_mmap module 2017-01-12 18:21:36 +08:00
lionsoul 387f5a2097 Merge branch 'master' of http://git.oschina.net/lionsoul/ip2region 2017-01-12 18:14:16 +08:00
lionsoul 9de920ef2b stdlize the code style and add the author info 2017-01-12 18:14:09 +08:00
我的上铺叫路遥 639c852534 Merge pull request !3 from 我的上铺叫路遥/master 2017-01-12 18:13:16 +08:00
Leo Ma 3c8cfa1282 Fix memory leak
Signed-off-by: Leo Ma <begeekmyfriend@gmail.com>
2017-01-12 18:04:07 +08:00
我的上铺叫路遥 a67936d835 Merge pull request !2 from 我的上铺叫路遥/master 2017-01-12 17:51:43 +08:00
Leo Ma 9bdf030fe0 Add database file memory map as c_mmap binding
File I/O optimization.

- No more `fread` call when the file is mapped.

- Close database file as soon as possible after `mmap`

Signed-off-by: Leo Ma <begeekmyfriend@gmail.com>
2017-01-12 17:33:58 +08:00
lionsoul 7a2b9943b5 stdlize the license add free statement 2016-12-28 09:53:13 +08:00
lionsoul c0955fedff update the merge&binary db file to version/2016/12/14 2016-12-21 16:53:14 +08:00
lionsoul 21bb060839 fix 10+ rows failed ip range records 2016-11-07 14:07:03 +08:00
lionsoul b0f7bff2de text and binary data version 2016/11/02 2016-11-05 21:13:36 +08:00
lionsoul 643e6a2463 update the db make doc and jar file 2016-11-03 17:32:16 +08:00
lionsoul ec395be524 add db make doc & update the CHANGES 2016-11-03 16:40:28 +08:00
lionsoul 7dcec80080 track the db make jar tools 2016-11-03 15:53:20 +08:00
lionsoul bedaca5b70 Merge pull request #4 from mohong122/master
golang实现
2016-10-20 17:08:17 +08:00
50 changed files with 199015 additions and 61467 deletions

10
.gitignore vendored
View File

@ -4,11 +4,21 @@
*.pyc *.pyc
*~ *~
META-INF/ META-INF/
# Binary Files # # Binary Files #
*.jar *.jar
!dbMaker-*.jar
# Package Files # # Package Files #
.settings/ .settings/
.classpath .classpath
.project .project
# vim swp file # # vim swp file #
*.swp *.swp
# binding
/binding/java/classes/
/binding/java/doc/
/binding/java/target/
/binding/java/*.jar

View File

@ -1,3 +1,34 @@
### 1.2.4
1, 花了近两周的时间重写了数据的升级算法,再次提高准确率,升级过程如下(此处应该有掌声):
```shell
1. ip预分段利于分布式同步升级
2. 分段同步升级,目前使用四个机器同时升级
3自动验证数据查缺补全
4数据合并
5数据格式标准化目前2个工作
1)ipip.net的数据和淘宝数据保持区域名称统一ipip.net的数据不带“省”和“市”关键字。
2)香港澳门台湾等国家信息修复淘宝原始数据有问题reported at http://git.oschina.net/lionsoul/ip2region/issues/21
6重复ip段的合并得到data目录下的ip.merge.txt
7生产data目录下的ip2region.db二进制数据库文件
```
2修复原始数据关于“香港台湾澳门”国家信息错误的bugreported at http://git.oschina.net/lionsoul/ip2region/issues/21
3将数据升级至2017/03/15同步版本
4增加c_mmap查询客户端C客户端查询文件读取使用内存映射加速感谢[Leo Ma](http://git.oschina.net/begeekmyfriend)的贡献
备注部分阿里云数据有问题缺失的部分使用免费开放的ipip.net的数据代替了。
### 1.2.3
1. 优化升级算法进行更深度的分裂可以使准确率再度提高同时数据的更新也花费了2天多的时间
2. 数据升级至2016/12/14版本的数据包括原始数据和binary数据库的数据
### 1.2.2
1. ip数据文件更新至2016/11/02版本
2. 增加ip2region.db数据库文件的java生成工具请参考README获取使用方式
3. 新增golang查询客户端的实现感谢 [@mohong122](https://github.com/mohong122) 的关注和贡献
### 1.2 ### 1.2
1. 新增分列式升级算法大大的增加了数据的准确率基本避免之前各大网友反馈的些许ip定位错误 1. 新增分列式升级算法大大的增加了数据的准确率基本避免之前各大网友反馈的些许ip定位错误

View File

@ -201,9 +201,9 @@
limitations under the License. limitations under the License.
========================================================================== ==========================================================================
The following license applies to the JQuery JavaScript library The following license applies to the ip2region library
-------------------------------------------------------------------------- --------------------------------------------------------------------------
Copyright (c) 2010 John Resig, http://jquery.com/ Copyright (c) 2015 Lionsoul<chenxin619315@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
@ -223,4 +223,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

109
README.md
View File

@ -1,27 +1,28 @@
ip2region - 最自由的ip地址查询库ip到地区的映射库提供Binary,B树和纯内存三种查询算法妈妈再也不用担心我的ip地址定位。 ip2region - 最自由的ip地址查询库ip到地区的映射库提供Binary,B树和纯内存三种查询算法妈妈再也不用担心我的ip地址定位。
**1. 99.9%准确率,定时更新:** ### 1. 99.9%准确率,定时更新:
数据聚合了一些知名ip到地名查询提供商的数据这些是他们官方的的准确率经测试着实比纯真啥的准确多了。<br /> 数据聚合了一些知名ip到地名查询提供商的数据这些是他们官方的的准确率经测试着实比纯真啥的准确多了。<br />
每次聚合一下数据需要1-2天会不定时更新。 每次聚合一下数据需要1-2天会不定时更新。
**2. 标准化的数据格式:** ### 2. 标准化的数据格式:
每条ip数据段都固定了格式_城市Id|国家|区域|省份|城市|ISP_ 每条ip数据段都固定了格式_城市Id|国家|区域|省份|城市|ISP_
只有中国的数据精确到了城市其他国家只能定位到国家后前的选项全部是0已经包含了全部你能查到的大大小小的国家。 只有中国的数据精确到了城市其他国家只能定位到国家后前的选项全部是0已经包含了全部你能查到的大大小小的国家。
请忽略前面的城市Id个人项目需求 请忽略前面的城市Id个人项目需求
**3. 体积小:** ### 3. 体积小:
生成的数据库文件ip2region.db只有1.5M1.2版本前是3.5M 生成的数据库文件ip2region.db只有1.5M1.2版本前是3.5M
**4. 多查询客户端的支持0.0x毫秒级别的查询** ### 4. 多查询客户端的支持0.0x毫秒级别的查询
已经集成的客户端有java, php, c, pythonnodejsphp扩展(支持linux, php5, php7版本已支持)。 已经集成的客户端有java, C#, php, c, pythonnodejsphp扩展(支持linux, php5, php7版本已支持)golang
提供了两种查询算法,响应时间如下: 提供了两种查询算法,响应时间如下:
客户端/binary算法/b-tree算法/Memory算法 客户端/binary算法/b-tree算法/Memory算法
c#/0.x毫秒/0.x毫秒/0.x毫秒
java/0.x毫秒/0.x毫秒/0.1x毫秒 (使用RandomAccessFile) java/0.x毫秒/0.x毫秒/0.1x毫秒 (使用RandomAccessFile)
php/0.x毫秒/0.1x毫秒/0.1x毫秒 php/0.x毫秒/0.1x毫秒/0.1x毫秒
c/0.0x毫秒/0.0x毫秒/0.00x毫秒(b-tree算法基本稳定在0.02x毫秒级别) c/0.0x毫秒/0.0x毫秒/0.00x毫秒(b-tree算法基本稳定在0.02x毫秒级别)
@ -29,38 +30,92 @@ ip2region - 最自由的ip地址查询库ip到地区的映射库提供Bina
任何客户端b-tree都比binary算法快当然Memory算法固然是最快的 任何客户端b-tree都比binary算法快当然Memory算法固然是最快的
**5. 测试程序:** maven仓库地址
java: ```xml
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.4</version>
</dependency>
```
nuget安装命令
```shell
Install-Package IP2Region
```
cd binding/java ### 5. 测试程序:
ant all c#:
java -jar ip2region-{version}.jar ./data/ip2region.db ```shell
cd IP2Region_ConsoleTest
dotnet run
example result:
请输入IP地址
36.149.160.55
```
java:
```shell
cd binding/java
ant all
java -jar ip2region-{version}.jar ./data/ip2region.db
```
php: php:
```shell
php binding/php/testSearcher ./data/ip2region.db php binding/php/testSearcher.php ./data/ip2region.db
```
c: c:
```shell
cd binding/c/ cd binding/c/
gcc -g -O2 testSearcher.c ip2region.c gcc -g -O2 testSearcher.c ip2region.c
./a.out ../../data/ip2region.db ./a.out ../../data/ip2region.db
```
python: python:
```shell
python binding/python/testSearcher ./data/ip2region.db python binding/python/testSearcher.py ./data/ip2region.db
```
均会看到如下界面: 均会看到如下界面:
```shell
initializing B-tree ... initializing B-tree ...
+----------------------------------+ +----------------------------------+
| ip2region test script | | ip2region test script |
| Author: chenxin619315@gmail.com | | Author: chenxin619315@gmail.com |
| Type 'quit' to exit program | | Type 'quit' to exit program |
+----------------------------------+ +----------------------------------+
p2region>> 101.105.35.57 p2region>> 101.105.35.57
2163|中国|华南|广东省|深圳市|鹏博士 in 0.02295 millseconds 2163|中国|华南|广东省|深圳市|鹏博士 in 0.02295 millseconds
```
输入ip地址开始测试第一次会稍微有点慢在运行命令后面接入binary,memory来尝试其他算法建议使用b-tree算法速度和并发需求的可以使用memory算法。 输入ip地址开始测试第一次会稍微有点慢在运行命令后面接入binary,memory来尝试其他算法建议使用b-tree算法速度和并发需求的可以使用memory算法。
具体集成请参考不同客户端的测试源码。 具体集成请参考不同客户端的测试源码。
### 6. 如何生成ip2region.db文件
从ip2region 1.2.2版本开始里面提交了一个dbMaker-{version}.jar的可以执行jar文件用它来完成这个工作
* 1, 确保你安装好了java环境不玩Java的童鞋就自己谷歌找找拉临时用一用几分钟的事情
* 2, cd到ip2region的根目录然后运行如下命令
```shell
java -jar dbMaker-{version}.jar -src 文本数据文件 -region 地域csv文件 [-dst 生成的ip2region.db文件的目录]
# 文本数据文件db文件的原始文本数据文件路径自带的ip2region.db文件就是/data/ip.merge.txt生成而来的你可以换成自己的或者更改/data/ip.merge.txt重新生成
# 地域csv文件该文件目的是方便配置ip2region进行数据关系的存储得到的数据包含一个city_id这个直接使用/data/origin/global_region.csv文件即可
# ip2region.db文件的目录是可选参数没有指定的话会在当前目录生成一份./data/ip2region.db文件
```
* 3, 获取生成的ip2region.db文件覆盖原来的ip2region.db文件即可
* 4, 默认的ip2region.db文件生成命令:
```shell
cd ip2region项目根目录
java -jar dbMaker-1.2.2.jar -src ./data/ip.merge.txt -region ./data/global_region.csv
# 会看到一大片的输出
```
* 5, 数据库文件的结构和原理请阅读 @冬芽 的blog[“ip2region数据库文件的结构和原理”](http://dongyado.com/tool/2016/08/18/structure-of-ip2region-database-file/)

View File

@ -0,0 +1,436 @@
//*******************************
// Create By Rocher Kong
// Github https://github.com/RocherKong
// Date 2018.02.09
//*******************************
using System;
using System.IO;
using System.Text;
namespace IP2Region
{
public class DbSearcher
{
public static int BTREE_ALGORITHM = 1;
public static int BINARY_ALGORITHM = 2;
public static int MEMORY_ALGORITYM = 3;
/**
* db config
*/
private DbConfig dbConfig = null;
/**
* db file access handler
*/
private FileStream raf = null;
/**
* header blocks buffer
*/
private long[] HeaderSip = null;
private int[] HeaderPtr = null;
private int headerLength;
/**
* super blocks info
*/
private long firstIndexPtr = 0;
private long lastIndexPtr = 0;
private int totalIndexBlocks = 0;
/**
* for memory mode
* the original db binary string
*/
private byte[] dbBinStr = null;
/**
* construct class
*
* @param bdConfig
* @param dbFile
* @throws FileNotFoundException
*/
public DbSearcher(DbConfig dbConfig, String dbFile)
{
this.dbConfig = dbConfig;
raf = new FileStream(dbFile, FileMode.Open, FileAccess.Read);
}
/**
* get the region with a int ip address with memory binary search algorithm
*
* @param ip
* @throws IOException
*/
public DataBlock MemorySearch(long ip)
{
int blen = IndexBlock.GetIndexBlockLength();
if (dbBinStr == null)
{
dbBinStr = new byte[(int)raf.Length];
raf.Seek(0L, SeekOrigin.Begin);
raf.Read(dbBinStr, 0, dbBinStr.Length);
//initialize the global vars
firstIndexPtr = Util.getIntLong(dbBinStr, 0);
lastIndexPtr = Util.getIntLong(dbBinStr, 4);
totalIndexBlocks = (int)((lastIndexPtr - firstIndexPtr) / blen) + 1;
}
//search the index blocks to define the data
int l = 0, h = totalIndexBlocks;
long sip, eip, dataptr = 0;
while (l <= h)
{
int m = (l + h) >> 1;
int p = (int)(firstIndexPtr + m * blen);
sip = Util.getIntLong(dbBinStr, p);
if (ip < sip)
{
h = m - 1;
}
else
{
eip = Util.getIntLong(dbBinStr, p + 4);
if (ip > eip)
{
l = m + 1;
}
else
{
dataptr = Util.getIntLong(dbBinStr, p + 8);
break;
}
}
}
//not matched
if (dataptr == 0) return null;
//get the data
int dataLen = (int)((dataptr >> 24) & 0xFF);
int dataPtr = (int)((dataptr & 0x00FFFFFF));
int city_id = (int)Util.getIntLong(dbBinStr, dataPtr);
String region = System.Text.Encoding.UTF8.GetString(dbBinStr, dataPtr + 4, dataLen - 4);//new String(dbBinStr, dataPtr + 4, dataLen - 4, Encoding.UTF8);
return new DataBlock(city_id, region, dataPtr);
}
/**
* get the region throught the ip address with memory binary search algorithm
*
* @param ip
* @return DataBlock
* @throws IOException
*/
public DataBlock MemorySearch(String ip)
{
return MemorySearch(Util.ip2long(ip));
}
/**
* get by index ptr
*
* @param indexPtr
* @throws IOException
*/
public DataBlock GetByIndexPtr(long ptr)
{
raf.Seek(ptr, SeekOrigin.Begin);
byte[]
buffer = new byte[12];
raf.Read(buffer, 0, buffer.Length);
//long startIp = Util.getIntLong(buffer, 0);
//long endIp = Util.getIntLong(buffer, 4);
long extra = Util.getIntLong(buffer, 8);
int dataLen = (int)((extra >> 24) & 0xFF);
int dataPtr = (int)((extra & 0x00FFFFFF));
raf.Seek(dataPtr, SeekOrigin.Begin);
byte[] data = new byte[dataLen];
raf.Read(data, 0, data.Length);
int city_id = (int)Util.getIntLong(data, 0);
String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);
//new String(data, 4, data.Length - 4, "UTF-8");
return new DataBlock(city_id, region, dataPtr);
}
/**
* get the region with a int ip address with b-tree algorithm
*
* @param ip
* @throws IOException
*/
public DataBlock BtreeSearch(long ip)
{
//check and load the header
if (HeaderSip == null)
{
raf.Seek(8L, SeekOrigin.Begin); //pass the super block
//byte[] b = new byte[dbConfig.getTotalHeaderSize()];
byte[] b = new byte[4096];
raf.Read(b, 0, b.Length);
//fill the header
int len = b.Length >> 3, idx = 0; //b.lenght / 8
HeaderSip = new long[len];
HeaderPtr = new int[len];
long startIp, dataPtrTemp;
for (int i = 0; i < b.Length; i += 8)
{
startIp = Util.getIntLong(b, i);
dataPtrTemp = Util.getIntLong(b, i + 4);
if (dataPtrTemp == 0) break;
HeaderSip[idx] = startIp;
HeaderPtr[idx] = (int)dataPtrTemp;
idx++;
}
headerLength = idx;
}
//1. define the index block with the binary search
if (ip == HeaderSip[0])
{
return GetByIndexPtr(HeaderPtr[0]);
}
else if (ip == HeaderSip[headerLength - 1])
{
return GetByIndexPtr(HeaderPtr[headerLength - 1]);
}
int l = 0, h = headerLength, sptr = 0, eptr = 0;
while (l <= h)
{
int m = (l + h) >> 1;
//perfetc matched, just return it
if (ip == HeaderSip[m])
{
if (m > 0)
{
sptr = HeaderPtr[m - 1];
eptr = HeaderPtr[m];
}
else
{
sptr = HeaderPtr[m];
eptr = HeaderPtr[m + 1];
}
break;
}
//less then the middle value
if (ip < HeaderSip[m])
{
if (m == 0)
{
sptr = HeaderPtr[m];
eptr = HeaderPtr[m + 1];
break;
}
else if (ip > HeaderSip[m - 1])
{
sptr = HeaderPtr[m - 1];
eptr = HeaderPtr[m];
break;
}
h = m - 1;
}
else
{
if (m == headerLength - 1)
{
sptr = HeaderPtr[m - 1];
eptr = HeaderPtr[m];
break;
}
else if (ip <= HeaderSip[m + 1])
{
sptr = HeaderPtr[m];
eptr = HeaderPtr[m + 1];
break;
}
l = m + 1;
}
}
//match nothing just stop it
if (sptr == 0) return null;
//2. search the index blocks to define the data
int blockLen = eptr - sptr, blen = IndexBlock.GetIndexBlockLength();
byte[]
iBuffer = new byte[blockLen + blen]; //include the right border block
raf.Seek(sptr, SeekOrigin.Begin);
raf.Read(iBuffer, 0, iBuffer.Length);
l = 0; h = blockLen / blen;
long sip, eip, dataptr = 0;
while (l <= h)
{
int m = (l + h) >> 1;
int p = m * blen;
sip = Util.getIntLong(iBuffer, p);
if (ip < sip)
{
h = m - 1;
}
else
{
eip = Util.getIntLong(iBuffer, p + 4);
if (ip > eip)
{
l = m + 1;
}
else
{
dataptr = Util.getIntLong(iBuffer, p + 8);
break;
}
}
}
//not matched
if (dataptr == 0) return null;
//3. get the data
int dataLen = (int)((dataptr >> 24) & 0xFF);
int dataPtr = (int)((dataptr & 0x00FFFFFF));
raf.Seek(dataPtr, SeekOrigin.Begin);
byte[] data = new byte[dataLen];
raf.Read(data, 0, data.Length);
int city_id = (int)Util.getIntLong(data, 0);
String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);// new String(data, 4, data.Length - 4, "UTF-8");
return new DataBlock(city_id, region, dataPtr);
}
/**
* get the region throught the ip address with b-tree search algorithm
*
* @param ip
* @return DataBlock
* @throws IOException
*/
public DataBlock BtreeSearch(String ip)
{
return BtreeSearch(Util.ip2long(ip));
}
/**
* get the region with a int ip address with binary search algorithm
*
* @param ip
* @throws IOException
*/
public DataBlock BinarySearch(long ip)
{
int blen = IndexBlock.GetIndexBlockLength();
if (totalIndexBlocks == 0)
{
raf.Seek(0L, SeekOrigin.Begin);
byte[] superBytes = new byte[8];
raf.Read(superBytes, 0, superBytes.Length);
//initialize the global vars
firstIndexPtr = Util.getIntLong(superBytes, 0);
lastIndexPtr = Util.getIntLong(superBytes, 4);
totalIndexBlocks = (int)((lastIndexPtr - firstIndexPtr) / blen) + 1;
}
//search the index blocks to define the data
int l = 0, h = totalIndexBlocks;
byte[]
buffer = new byte[blen];
long sip, eip, dataptr = 0;
while (l <= h)
{
int m = (l + h) >> 1;
raf.Seek(firstIndexPtr + m * blen, SeekOrigin.Begin); //set the file pointer
raf.Read(buffer, 0, buffer.Length);
sip = Util.getIntLong(buffer, 0);
if (ip < sip)
{
h = m - 1;
}
else
{
eip = Util.getIntLong(buffer, 4);
if (ip > eip)
{
l = m + 1;
}
else
{
dataptr = Util.getIntLong(buffer, 8);
break;
}
}
}
//not matched
if (dataptr == 0) return null;
//get the data
int dataLen = (int)((dataptr >> 24) & 0xFF);
int dataPtr = (int)((dataptr & 0x00FFFFFF));
raf.Seek(dataPtr, SeekOrigin.Begin);
byte[] data = new byte[dataLen];
raf.Read(data, 0, data.Length);
int city_id = (int)Util.getIntLong(data, 0);
String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);//new String(data, 4, data.Length - 4, "UTF-8");
return new DataBlock(city_id, region, dataPtr);
}
/**
* get the region throught the ip address with binary search algorithm
*
* @param ip
* @return DataBlock
* @throws IOException
*/
public DataBlock BinarySearch(String ip)
{
return BinarySearch(Util.ip2long(ip));
}
/**
* get the db config
*
* @return DbConfig
*/
public DbConfig GetDbConfig()
{
return dbConfig;
}
/**
* close the db
*
* @throws IOException
*/
public void Close()
{
HeaderSip = null; //let gc do its work
HeaderPtr = null;
dbBinStr = null;
raf.Close();
}
}
}

View File

@ -0,0 +1,92 @@
//*******************************
// Create By Rocher Kong
// Github https://github.com/RocherKong
// Date 2018.02.09
//*******************************
using System;
using System.Text;
namespace IP2Region
{
public class DataBlock
{
/**
* city id
*/
private int city_id;
/**
* region address
*/
private String region;
/**
* region ptr in the db file
*/
private int dataPtr;
/**
* construct method
*
* @param city_id
* @param region region string
* @param ptr data ptr
*/
public DataBlock(int city_id, String region, int dataPtr)
{
this.city_id = city_id;
this.region = region;
this.dataPtr = dataPtr;
}
public DataBlock(int city_id, String region)
{
this.city_id = city_id;
this.region = region;
this.dataPtr = 0;
}
public int GetCityId()
{
return city_id;
}
public DataBlock SetCityId(int city_id)
{
this.city_id = city_id;
return this;
}
public String GetRegion()
{
return region;
}
public DataBlock SetRegion(String region)
{
this.region = region;
return this;
}
public int GetDataPtr()
{
return dataPtr;
}
public DataBlock SetDataPtr(int dataPtr)
{
this.dataPtr = dataPtr;
return this;
}
public override String ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(city_id).Append('|').Append(region).Append('|').Append(dataPtr);
return sb.ToString();
}
}
}

View File

@ -0,0 +1,69 @@
//*******************************
// Create By Rocher Kong
// Github https://github.com/RocherKong
// Date 2018.02.09
//*******************************
using System;
namespace IP2Region
{
public class DbConfig
{
/**
* total header data block size
*/
private int totalHeaderSize;
/**
* max index data block size
* u should always choice the fastest read block size
*/
private int indexBlockSize;
/**
* construct method
*
* @param totalHeaderSize
* @param dataBlockSize
* @throws DbMakerConfigException
*/
public DbConfig(int totalHeaderSize)
{
if ((totalHeaderSize % 8) != 0)
{
throw new DbMakerConfigException("totalHeaderSize must be times of 8");
}
this.totalHeaderSize = totalHeaderSize;
this.indexBlockSize = 8192; //4 * 2048
}
public DbConfig()
{
this.totalHeaderSize = 8 * 2048;
this.indexBlockSize = 8192;
}
public int GetTotalHeaderSize()
{
return totalHeaderSize;
}
public DbConfig SetTotalHeaderSize(int totalHeaderSize)
{
this.totalHeaderSize = totalHeaderSize;
return this;
}
public int GetIndexBlockSize()
{
return indexBlockSize;
}
public DbConfig SetIndexBlockSize(int dataBlockSize)
{
this.indexBlockSize = dataBlockSize;
return this;
}
}
}

View File

@ -0,0 +1,16 @@
//*******************************
// Create By Rocher Kong
// Github https://github.com/RocherKong
// Date 2018.02.09
//*******************************
namespace IP2Region
{
public class DbMakerConfigException : System.Exception
{
public string ErrorCode { get; set; }
public DbMakerConfigException(string ErrorCode)
{
this.ErrorCode=ErrorCode;
}
}
}

View File

@ -0,0 +1,73 @@
//*******************************
// Create By Rocher Kong
// Github https://github.com/RocherKong
// Date 2018.02.09
//*******************************
using System;
namespace IP2Region
{
public class HeaderBlock
{
/**
* index block start ip address
*/
private long indexStartIp;
/**
* ip address
*/
private int indexPtr;
public HeaderBlock(long indexStartIp, int indexPtr)
{
this.indexStartIp = indexStartIp;
this.indexPtr = indexPtr;
}
public long GetIndexStartIp()
{
return indexStartIp;
}
public HeaderBlock SetIndexStartIp(long indexStartIp)
{
this.indexStartIp = indexStartIp;
return this;
}
public int GetIndexPtr()
{
return indexPtr;
}
public HeaderBlock SetIndexPtr(int indexPtr)
{
this.indexPtr = indexPtr;
return this;
}
/**
* get the bytes for db storage
*
* @return byte[]
*/
public byte[] GetBytes()
{
/*
* +------------+-----------+
* | 4bytes | 4bytes |
* +------------+-----------+
* start ip index ptr
*/
byte[] b = new byte[8];
Util.writeIntLong(b, 0, indexStartIp);
Util.writeIntLong(b, 4, indexPtr);
return b;
}
}
}

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Rocher</Authors>
<Company>Rocher</Company>
<Description>准确率99.9%的ip地址定位库0.0x毫秒级查询, 支持Binary,B树,内存三种查询算法妈妈再也不用担心我的ip地址定位</Description>
<PackageReleaseNotes>ip2region - 最自由的ip地址查询库ip到地区的映射库提供Binary,B树和纯内存三种查询算法妈妈再也不用担心我的ip地址定位。</PackageReleaseNotes>
<Copyright>Rocher</Copyright>
<PackageTags>ip2region c# IP</PackageTags>
<RepositoryUrl>https://gitee.com/rocherkong/IP2Region</RepositoryUrl>
<Version>1.1.0</Version>
</PropertyGroup>
<ItemGroup>
<None Update="DBFile\ip2region.db">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,117 @@
//*******************************
// Create By Rocher Kong
// Github https://github.com/RocherKong
// Date 2018.02.09
//*******************************
using System;
namespace IP2Region
{
public class IndexBlock
{
private static int LENGTH = 12;
/**
* start ip address
*/
private long startIp;
/**
* end ip address
*/
private long endIp;
/**
* data ptr and data length
*/
private uint dataPtr;
/**
* data length
*/
private int dataLen;
public IndexBlock(long startIp, long endIp, uint dataPtr, int dataLen)
{
this.startIp = startIp;
this.endIp = endIp;
this.dataPtr = dataPtr;
this.dataLen = dataLen;
}
public long GetStartIp()
{
return startIp;
}
public IndexBlock SetStartIp(long startIp)
{
this.startIp = startIp;
return this;
}
public long GetEndIp()
{
return endIp;
}
public IndexBlock SetEndIp(long endIp)
{
this.endIp = endIp;
return this;
}
public uint GetDataPtr()
{
return dataPtr;
}
public IndexBlock SetDataPtr(uint dataPtr)
{
this.dataPtr = dataPtr;
return this;
}
public int GetDataLen()
{
return dataLen;
}
public IndexBlock SetDataLen(int dataLen)
{
this.dataLen = dataLen;
return this;
}
public static int GetIndexBlockLength()
{
return LENGTH;
}
/**
* get the bytes for storage
*
* @return byte[]
*/
public byte[] GetBytes()
{
/*
* +------------+-----------+-----------+
* | 4bytes | 4bytes | 4bytes |
* +------------+-----------+-----------+
* start ip end ip data ptr + len
*/
byte[] b = new byte[12];
Util.writeIntLong(b, 0, startIp); //start ip
Util.writeIntLong(b, 4, endIp); //end ip
//write the data ptr and the length
long mix = dataPtr | ((dataLen << 24) & 0xFF000000L);
Util.writeIntLong(b, 8, mix);
return b;
}
}
}

View File

@ -0,0 +1,162 @@
//*******************************
// Create By Rocher Kong
// Github https://github.com/RocherKong
// Date 2018.02.09
//*******************************
using System;
using System.Globalization;
using System.Text;
namespace IP2Region
{
public class Util
{
/**
* write specfield bytes to a byte array start from offset
*
* @param b
* @param offset
* @param v
* @param bytes
*/
public static void write(byte[] b, int offset, ulong v, int bytes)
{
for (int i = 0; i < bytes; i++)
{
b[offset++] = (byte)((v >> (8 * i)) & 0xFF);
}
}
/**
* write a int to a byte array
*
* @param b
* @param offet
* @param v
*/
public static void writeIntLong(byte[] b, int offset, long v)
{
b[offset++] = (byte)((v >> 0) & 0xFF);
b[offset++] = (byte)((v >> 8) & 0xFF);
b[offset++] = (byte)((v >> 16) & 0xFF);
b[offset] = (byte)((v >> 24) & 0xFF);
}
/**
* get a int from a byte array start from the specifiled offset
*
* @param b
* @param offset
*/
public static long getIntLong(byte[] b, int offset)
{
return (
((b[offset++] & 0x000000FFL)) |
((b[offset++] << 8) & 0x0000FF00L) |
((b[offset++] << 16) & 0x00FF0000L) |
((b[offset] << 24) & 0xFF000000L)
);
}
/**
* get a int from a byte array start from the specifield offset
*
* @param b
* @param offset
*/
public static int getInt3(byte[] b, int offset)
{
return (
(b[offset++] & 0x000000FF) |
(b[offset++] & 0x0000FF00) |
(b[offset] & 0x00FF0000)
);
}
public static int getInt2(byte[] b, int offset)
{
return (
(b[offset++] & 0x000000FF) |
(b[offset] & 0x0000FF00)
);
}
public static int getInt1(byte[] b, int offset)
{
return (
(b[offset] & 0x000000FF)
);
}
/**
* string ip to long ip
*
* @param ip
* @return long
*/
public static long ip2long(string ip)
{
string[] p = ip.Split('.');
if (p.Length != 4) return 0;
var bip1 = long.TryParse(p[0], out long ip1);
var bip2 = long.TryParse(p[1], out long ip2);
var bip3 = long.TryParse(p[2], out long ip3);
var bip4 = long.TryParse(p[3], out long ip4);
if (!bip1 || !bip2 || !bip3 || !bip4
|| ip4 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255
|| ip4 < 1 || ip1 < 1 || ip2 < 1 || ip3 < 1)
{
throw new Exception("IP Illegal.");
}
long p1 = ((ip1 << 24) & 0xFF000000);
long p2 = ((ip2 << 16) & 0x00FF0000);
long p3 = ((ip3 << 8) & 0x0000FF00);
long p4 = ((ip4 << 0) & 0x000000FF);
return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL);
}
/**
* int to ip string
*
* @param ip
* @return string
*/
public static string long2ip(long ip)
{
StringBuilder sb = new StringBuilder();
sb
.Append((ip >> 24) & 0xFF).Append('.')
.Append((ip >> 16) & 0xFF).Append('.')
.Append((ip >> 8) & 0xFF).Append('.')
.Append((ip >> 0) & 0xFF);
return sb.ToString();
}
/**
* check the validate of the specifeld ip address
*
* @param ip
* @return boolean
*/
public static Boolean isIpAddress(string ip)
{
string[] p = ip.Split('.');
if (p.Length != 4) return false;
foreach (string pp in p)
{
if (pp.Length > 3) return false;
int val = int.Parse(pp);
if (val > 255) return false;
}
return true;
}
}
}

Binary file not shown.

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\IP2Region\IP2Region.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="netstandard">
<HintPath>C:\Program Files (x86)\Microsoft SDKs\NuGetPackagesFallback\netstandard.library\2.0.1\build\netstandard2.0\ref\netstandard.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Update="DBFile\ip2region.db">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,50 @@
using IP2Region;
using System;
using System.Diagnostics;
namespace IP2Region_ConsoleTest
{
class Program
{
static void Main(string[] args)
{
DbSearcher dbSearcher = new DbSearcher(new DbConfig
{
}, AppContext.BaseDirectory + @"/DBFile/ip2region.db");
string ipAddress = "";
DataBlock result = null, result2 = null,result3=null;
Console.WriteLine("请输入IP地址");
ipAddress = Console.ReadLine();
Stopwatch sw = new Stopwatch();
do
{
sw.Start();
try
{
result = dbSearcher.BtreeSearch(ipAddress);
sw.Stop();
Console.WriteLine("[btree]你的IP所属区域为" + result.GetRegion() + ";耗时:" + sw.Elapsed.TotalMilliseconds + "ms");
sw.Start();
result2 = dbSearcher.BinarySearch(ipAddress);
sw.Stop();
Console.WriteLine("[binarySearch]你的IP所属区域为" + result2.GetRegion() + ";耗时:" + sw.Elapsed.TotalMilliseconds + "ms");
sw.Start();
result3 = dbSearcher.MemorySearch(ipAddress);
sw.Stop();
Console.WriteLine("[MemorySearch]你的IP所属区域为" + result3.GetRegion() + ";耗时:" + sw.Elapsed.TotalMilliseconds + "ms");
Console.WriteLine("请输入IP地址");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
sw.Stop();
}
//Console.WriteLine("结束请输入bye");
} while ((ipAddress = Console.ReadLine()) != "bye");
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<TargetFramework>netcoreapp2.0</TargetFramework>
<PublishDir>bin\Release\PublishOutput</PublishDir>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

View File

@ -43,7 +43,9 @@ typedef unsigned int uint_t;
typedef unsigned long ulong_t; typedef unsigned long ulong_t;
#define INDEX_BLOCK_LENGTH 12 #define INDEX_BLOCK_LENGTH 12
#define TOTAL_HEADER_LENGTH 4096
//thats 8 * 1024
#define TOTAL_HEADER_LENGTH 8192
/* /*
* ip2region properties struct * ip2region properties struct

328
binding/c_mmap/ip2region.c Normal file
View File

@ -0,0 +1,328 @@
/**
* ip2region implementation with mmap support created by Leo Ma
*
* @see #ip2region.h
* @author chenxin<chenxin619315@gmail.com>
* @author Leo Ma<http://git.oschina.net/begeekmyfriend>
* @date 2017/01/12
*/
#include "ip2region.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
/**
* create a new ip2region object
*
* @param dbFile path
*/
IP2R_API uint_t ip2region_create(ip2region_t ip2rObj, char *dbFile)
{
struct stat st;
memset(ip2rObj, 0x00, sizeof(ip2region_entry));
ip2rObj->dbFile = IP2R_MALLOC(1024);
strcpy(ip2rObj->dbFile, dbFile);
int fd = open(dbFile, O_RDONLY);
if ( fd < 0 ) {
//fprintf(stderr, "Fail to open the db file %s\n", ip2rObj->dbFile);
return 0;
}
if ( fstat(fd, &st) < 0 ) {
//fprintf(stderr, "Fail to stat the db file %s\n", ip2rObj->dbFile);
return 0;
}
ip2rObj->dbSize = st.st_size;
ip2rObj->dbBinStr = mmap(NULL, ip2rObj->dbSize, PROT_READ, MAP_PRIVATE, fd, 0);
if ( ip2rObj->dbBinStr == (void *) -1 ) {
//fprintf(stderr, "Fail to map the db file %s\n", ip2rObj->dbFile);
return 0;
}
// Close db file as soon as possible.
close(fd);
ip2rObj->headerLen = 0;
ip2rObj->HeaderSip = (uint_t *) IP2R_MALLOC(TOTAL_HEADER_LENGTH);
if ( ip2rObj->HeaderSip == NULL ) {
return 0;
}
ip2rObj->HeaderPtr = (uint_t *) IP2R_MALLOC(TOTAL_HEADER_LENGTH);
if ( ip2rObj->HeaderPtr == NULL ) {
IP2R_FREE(ip2rObj->HeaderSip);
return 0;
}
ip2rObj->firstIndexPtr = getUnsignedInt(ip2rObj->dbBinStr, 0);
ip2rObj->lastIndexPtr = getUnsignedInt(ip2rObj->dbBinStr, 4);
ip2rObj->totalBlocks = (ip2rObj->lastIndexPtr-ip2rObj->firstIndexPtr)/INDEX_BLOCK_LENGTH + 1;
return 1;
}
/**
* destroy the specifield ip2region object
*
* @param ip2region_t
*/
IP2R_API uint_t ip2region_destroy(ip2region_t ip2rObj)
{
IP2R_FREE(ip2rObj->dbFile);
IP2R_FREE(ip2rObj->HeaderSip);
IP2R_FREE(ip2rObj->HeaderPtr);
//free the db binary string
if ( ip2rObj->dbBinStr != NULL ) {
munmap(ip2rObj->dbBinStr, ip2rObj->dbSize);
}
memset(ip2rObj, 0x00, sizeof(ip2region_entry));
return 1;
}
/**
* get the region associated with the specified ip address with the memory binary search algorithm
*
* @param ip2rObj
* @param ip
* @param datablock
*/
IP2R_API uint_t ip2region_binary_search(ip2region_t ip2rObj, uint_t ip, datablock_t datablock)
{
int l, h, m, p;
uint_t sip, eip, dptr;
int dataLen, dataptr;
char *buffer;
l = 0; h = ip2rObj->totalBlocks; dptr = 0;
while ( l <= h ) {
m = (l + h) >> 1;
p = ip2rObj->firstIndexPtr + m * INDEX_BLOCK_LENGTH;
buffer = ip2rObj->dbBinStr + p;
sip = getUnsignedInt(buffer, 0);
if ( ip < sip ) {
h = m - 1;
} else {
eip = getUnsignedInt(buffer, 4);
if ( ip > eip ) {
l = m + 1;
} else {
dptr = getUnsignedInt(buffer, 8);
break;
}
}
}
if ( dptr == 0 ) return 0;
//get the data
dataLen = ((dptr >> 24) & 0xFF);
dataptr = (dptr & 0x00FFFFFF);
buffer = ip2rObj->dbBinStr + dataptr;
//fill the data to the datablock
datablock->city_id = getUnsignedInt(buffer, 0);
dataLen -= 4; //reduce the length of the city_id
memcpy(datablock->region, buffer + 4, dataLen);
datablock->region[dataLen] = '\0';
return 1;
}
IP2R_API uint_t ip2region_binary_search_string(ip2region_t ip2rObj, char *ip, datablock_t datablock)
{
return ip2region_binary_search(ip2rObj, ip2long(ip), datablock);
}
/**
* get the region associated with the specifield ip address with b-tree algorithm
*
* @param ip2rObj
* @param ip
* @param datablock
* @return uint_t
*/
IP2R_API uint_t ip2region_btree_search(ip2region_t ip2rObj, uint_t ip, datablock_t datablock)
{
int i, j;
int l, m, h, p, sptr, eptr, indexBlockLen, dataLen, dataptr;
uint_t sip, eip, idxptr, dptr;
char *buffer;
if ( ip2rObj->headerLen == 0 ) {
buffer = ip2rObj->dbBinStr + 8;
for ( i = j = 0; i < TOTAL_HEADER_LENGTH; i += 8, j++ ) {
sip = getUnsignedInt(buffer, i);
idxptr = getUnsignedInt(buffer, i + 4);
if ( idxptr == 0 ) break;
ip2rObj->HeaderSip[j] = sip;
ip2rObj->HeaderPtr[j] = idxptr;
}
ip2rObj->headerLen = j;
}
//search the header block to define the index block
l = 0; h = ip2rObj->headerLen; sptr = 0; eptr = 0;
while ( l <= h ) {
m = ((l + h) >> 1);
//perfetc matched, just return it
if ( ip == ip2rObj->HeaderSip[m] ) {
if ( m > 0 ) {
sptr = ip2rObj->HeaderPtr[m-1];
eptr = ip2rObj->HeaderPtr[m ];
} else {
sptr = ip2rObj->HeaderPtr[m ];
eptr = ip2rObj->HeaderPtr[m+1];
}
break;
}
//less then the middle value
if ( ip < ip2rObj->HeaderSip[m] ) {
if ( m == 0 ) {
sptr = ip2rObj->HeaderPtr[m ];
eptr = ip2rObj->HeaderPtr[m+1];
break;
} else if ( ip > ip2rObj->HeaderSip[m-1] ) {
sptr = ip2rObj->HeaderPtr[m-1];
eptr = ip2rObj->HeaderPtr[m ];
break;
}
h = m - 1;
} else {
if ( m == ip2rObj->headerLen - 1 ) {
sptr = ip2rObj->HeaderPtr[m-1];
eptr = ip2rObj->HeaderPtr[m ];
break;
} else if ( ip <= ip2rObj->HeaderSip[m+1] ) {
sptr = ip2rObj->HeaderPtr[m ];
eptr = ip2rObj->HeaderPtr[m+1];
break;
}
l = m + 1;
}
}
//not matched just stop it
if ( sptr == 0 ) return 0;
indexBlockLen = eptr - sptr;
buffer = ip2rObj->dbBinStr + sptr;
dptr = 0; l = 0; h = indexBlockLen / INDEX_BLOCK_LENGTH;
while ( l <= h ) {
m = ((l + h) >> 1);
p = m * INDEX_BLOCK_LENGTH;
sip = getUnsignedInt(buffer, p);
if ( ip < sip ) {
h = m - 1;
} else {
eip = getUnsignedInt(buffer, p + 4);
if ( ip > eip ) {
l = m + 1;
} else {
dptr = getUnsignedInt(buffer, p + 8);
break;
}
}
}
if ( dptr == 0 ) return 0;
dataLen = ((dptr >> 24) & 0xFF);
dataptr = (dptr & 0x00FFFFFF);
buffer = ip2rObj->dbBinStr + dataptr;
datablock->city_id = getUnsignedInt(buffer, 0);
dataLen -= 4;
memcpy(datablock->region, buffer + 4, dataLen);
datablock->region[dataLen] = '\0';
return 1;
}
IP2R_API uint_t ip2region_btree_search_string(ip2region_t ip2rObj, char *ip, datablock_t datablock)
{
return ip2region_btree_search(ip2rObj, ip2long(ip), datablock);
}
/**
* get a unsinged long(4bytes) from a specifield buffer start from the specifield offset
*
* @param buffer
* @param offset
* @return uint_t
*/
IP2R_API uint_t getUnsignedInt(char *buffer, int offset)
{
return (
((buffer[offset ]) & 0x000000FF) |
((buffer[offset+1] << 8) & 0x0000FF00) |
((buffer[offset+2] << 16) & 0x00FF0000) |
((buffer[offset+3] << 24) & 0xFF000000)
);
}
/**
* string ip to long
*
* @param ip
* @return uint_t
*/
IP2R_API uint_t ip2long(char *ip)
{
int i = 0, p = 24;
char buffer[4], *cs = ip;
uint_t ipval = 0;
while ( *cs != '\0' ) {
if ( *cs == '.' ) {
//single part length limit
if ( i > 3 ) {
ipval = 0;
break;
}
if ( p < 0 ) break;
buffer[i] = '\0';
ipval |= (atoi(buffer) << p);
p -= 8;
i = 0;
} else {
buffer[i++] = *cs;
}
cs++;
}
//append the rest parts
if ( i > 3 ) return 0;
buffer[i] = '\0';
ipval |= atoi(buffer);
return ipval;
}
/**
* long to string ip
*
* @param ip
* @param buffer
* @return uint_t(1 for success and 0 for failed)
*/
IP2R_API uint_t long2ip(uint_t ip, char *buffer)
{
return 0;
}

138
binding/c_mmap/ip2region.h Normal file
View File

@ -0,0 +1,138 @@
/**
* ip2region header file
*
* @author chenxin<chenxin619315@gmail.com>
* @author Leo Ma<http://git.oschina.net/begeekmyfriend>
*/
#ifndef _IP2REGION_H
#define _IP2REGION_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//yat, just take it as this way, 99 percent and they works find
#if ( defined(_WIN32) || defined(_WINDOWS_) || defined(__WINDOWS_) )
# define OS_WINDOW
#else
# define OS_LINUX
#endif
#ifdef OS_WINDOW
# define IP2R_API extern __declspec(dllexport)
#else
/*platform shared library statement :: unix*/
# define IP2R_API extern
#endif
#define print(str) printf("%s", str)
#define println(str) printf("%s\n", str)
/*
* memory allocation macro definition.
* cause we should use emalloc,ecalloc .ege. in php.
* so you could make it better apdat the php environment.
*/
#define IP2R_CALLOC(_bytes, _blocks) calloc(_bytes, _blocks)
#define IP2R_MALLOC(_bytes) malloc(_bytes)
#define IP2R_FREE(_ptr) free(_ptr)
typedef unsigned short ushort_t;
typedef unsigned char uchar_t;
typedef unsigned int uint_t;
typedef unsigned long ulong_t;
#define INDEX_BLOCK_LENGTH 12
#define TOTAL_HEADER_LENGTH 8192
/*
* ip2region properties struct
*/
typedef struct {
uint_t *HeaderSip; //header start ip blocks
uint_t *HeaderPtr; //header ptr blocks
uint_t headerLen; //header block number
char *dbFile; //path of db file
char *dbBinStr; //db binary string for memory search mode
uint_t dbSize;
uint_t firstIndexPtr; //first index ptr
uint_t lastIndexPtr; //last index ptr
uint_t totalBlocks; //total index blocks number
} ip2region_entry;
typedef ip2region_entry * ip2region_t;
/*
* data block
*/
typedef struct {
uint_t city_id;
char region[256];
} datablock_entry;
typedef datablock_entry * datablock_t;
/**
* create a new ip2region object
*
* @param ip2rObj
* @param dbFile path
*/
IP2R_API uint_t ip2region_create(ip2region_t, char *);
/**
* destroy the specified ip2region object
*
* @param ip2region_t
*/
IP2R_API uint_t ip2region_destroy(ip2region_t);
/**
* get the region associated with the specified ip address with memory binary search algorithm
*
* @param ip2region_t
* @param uint_t
* @param datablock_t
* @date 2016/06/30
*/
IP2R_API uint_t ip2region_binary_search(ip2region_t, uint_t, datablock_t);
IP2R_API uint_t ip2region_binary_search_string(ip2region_t, char *, datablock_t);
/**
* get the region associated with the specified ip address with b-tree algorithm
*
* @param ip2rObj
* @param ip
* @param datablock
* @return uint_t
*/
IP2R_API uint_t ip2region_btree_search(ip2region_t, uint_t, datablock_t);
IP2R_API uint_t ip2region_btree_search_string(ip2region_t, char *, datablock_t);
/**
* get a unsinged long(4bytes) from a specified buffer start from the specified offset
*
* @param buffer
* @param offset
* @return uint_t
*/
IP2R_API uint_t getUnsignedInt(char *, int);
/**
* string ip to long
*
* @param ip
* @return uint_t
*/
IP2R_API uint_t ip2long(char *);
/**
* long to string ip
*
* @param ip
* @param buffer
* @return uint_t(1 for success and 0 for failed)
*/
IP2R_API uint_t long2ip(uint_t, char *);
#endif /*end ifndef*/

View File

@ -0,0 +1,99 @@
/**
* test ip2region searcher program
*
* @author chenxin<chenxin619315@gmail.com>
* @date 2015-10-30
*/
#include "ip2region.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#define __PRINT_ABOUT__ \
println("+-------------------------------------+"); \
println("| ip2region test program |"); \
println("| Author: chenxin619315@gmail.com. |"); \
println("| Type 'quit' to exit the program. |"); \
println("+-------------------------------------+");
//read a line from a command line.
static char *getLine( FILE *fp, char *__dst )
{
register int c;
register char *cs;
cs = __dst;
while ( ( c = getc( fp ) ) != EOF ) {
if ( c == '\n' ) break;
*cs++ = c;
}
*cs = '\0';
return ( c == EOF && cs == __dst ) ? NULL : __dst;
}
static double getTime()
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
return (tv.tv_sec * 1000 + ((double)tv.tv_usec)/1000);
}
int main( int argc, char **argv )
{
ip2region_entry ip2rEntry;
datablock_entry datablock;
char *dbFile = NULL, *algorithm = NULL;
char line[256];
uint_t (*func_ptr)(ip2region_t, char *, datablock_t);
double s_time, c_time;
memset(&datablock, 0x00, sizeof(datablock_entry));
if ( argc < 2 ) {
printf("Usage: a.out [ip2region db file path] [algorithm]\n");
return 0;
}
dbFile = argv[1];
algorithm = "B-tree";
func_ptr = ip2region_btree_search_string;
if ( argc >= 3 ) {
if ( strcmp(argv[2], "binary") == 0 ) {
algorithm = "File";
func_ptr = ip2region_binary_search_string;
}
}
//create a new ip2rObj
printf("+--initializing %s ... \n", algorithm);
if ( ip2region_create(&ip2rEntry, dbFile) == 0 ) {
println("Error: Fail to create the ip2region object\n");
return 0;
}
__PRINT_ABOUT__;
while ( 1 ) {
print("ip2region>> ");
getLine( stdin, line );
if ( strlen(line) < 2 ) continue;
if ( strcasecmp( line, "quit" ) == 0 ) {
println("+--Bye!");
break;
}
s_time = getTime();
func_ptr(&ip2rEntry, line, &datablock);
c_time = getTime() - s_time;
printf("%d|%s in %.5f millseconds\n", datablock.city_id, datablock.region, c_time);
}
//destory the ip2rObj
ip2region_destroy(&ip2rEntry);
return 0;
}

View File

@ -9,8 +9,8 @@ import (
) )
const ( const (
INDEX_BLOCK_LENGTH = 12 INDEX_BLOCK_LENGTH = 12
TOTAL_HEADER_LENGTH = 4096 TOTAL_HEADER_LENGTH = 8192
) )
var err error var err error

View File

@ -9,7 +9,7 @@
<property name="jars" value="${basedir}"/> <property name="jars" value="${basedir}"/>
<property name="sources" value="${basedir}/src"/> <property name="sources" value="${basedir}/src"/>
<property name="classes" value="${basedir}/classes"/> <property name="classes" value="${basedir}/classes"/>
<property name="version" value="1.2"/> <property name="version" value="1.4"/>
<property name="api" value="${basedir}/doc"/> <property name="api" value="${basedir}/doc"/>
<mkdir dir="${classes}"/> <mkdir dir="${classes}"/>
<mkdir dir="${api}"/> <mkdir dir="${api}"/>

190
binding/java/pom.xml Normal file
View File

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.4</version>
<packaging>jar</packaging>
<name>ip2region</name>
<url>http://gitee.com/lionsoul/ip2region/</url>
<description>Open source internel address locator</description>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>git@gitee.com:lionsoul/ip2region.git</url>
<connection>scm:git:git@gitee.com:lionsoul/ip2region.git</connection>
<developerConnection>scm:git:git@gitee.com:lionsoul/ip2region.git</developerConnection>
</scm>
<developers>
<developer>
<id>lionsoul</id>
<name>chenxin</name>
<email>chenxin619315@gmail.com</email>
</developer>
</developers>
<issueManagement>
<url>http://gitee.com/lionsoul/ip2region/issues</url>
<system>gitee issues</system>
</issueManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalparam>${javadoc.opts}</additionalparam>
</configuration>
</execution>
</executions>
<configuration>
<failOnError>false</failOnError>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.lionsoul.ip2region.test.TestSearcher</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>java8-doclint-disabled</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<properties>
<javadoc.opts>-Xdoclint:none</javadoc.opts>
</properties>
</profile>
<profile>
<id>release</id>
<build>
<plugins>
<!-- Source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalparam>${javadoc.opts}</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
<!-- GPG -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>oss-parent</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>oss-parent</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</profile>
</profiles>
</project>

View File

@ -32,12 +32,12 @@ public class DbConfig
} }
this.totalHeaderSize = totalHeaderSize; this.totalHeaderSize = totalHeaderSize;
this.indexBlockSize = 4096; //4 * 1024 this.indexBlockSize = 8192; //4 * 2048
} }
public DbConfig() throws DbMakerConfigException public DbConfig() throws DbMakerConfigException
{ {
this(8192); this(8 * 2048);
} }
public int getTotalHeaderSize() public int getTotalHeaderSize()

1
binding/nodejs/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

View File

@ -1,3 +1,3 @@
# nodejs 客户端 # nodejs 客户端
现已实现同步查询,异步查询未实现,用法参考 test.js 现已实现同步查询,异步查询未实现,用法参考 ip2region.spec.js

View File

@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`binarySearch 1`] = `
Object {
"city": 2163,
"region": "中国|华南|广东省|深圳市|阿里云",
}
`;
exports[`binarySearch 2`] = `
Object {
"city": 0,
"region": "未分配或者内网IP|0|0|0|0",
}
`;
exports[`should query 1`] = `
Object {
"city": 2163,
"region": "中国|华南|广东省|深圳市|阿里云",
}
`;
exports[`should query 2`] = `
Object {
"city": 0,
"region": "未分配或者内网IP|0|0|0|0",
}
`;

View File

@ -18,7 +18,7 @@ var lastIndexPtr = 0;
var superBlock = new Buffer(8); var superBlock = new Buffer(8);
var indexBlockLength = 12; var indexBlockLength = 12;
var totalHeaderLength = 4096; var totalHeaderLength = 8192;
/** /**

View File

@ -0,0 +1,15 @@
'use strict';
const ip = require('./ip2region');
const query = ip.create('../../data/ip2region.db');
it('should query', () => {
expect(query.btreeSearchSync('120.24.78.68')).toMatchSnapshot();
expect(query.btreeSearchSync('10.10.10.10')).toMatchSnapshot();
});
it('binarySearch', () => {
expect(query.binarySearchSync('120.24.78.68')).toMatchSnapshot();
expect(query.binarySearchSync('10.10.10.10')).toMatchSnapshot();
});

View File

@ -4,7 +4,7 @@
"description": "ip database ", "description": "ip database ",
"main": "ip2region.js", "main": "ip2region.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "jest"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -20,5 +20,8 @@
"bugs": { "bugs": {
"url": "https://github.com/lionsoul2016/ip2region/issues" "url": "https://github.com/lionsoul2016/ip2region/issues"
}, },
"homepage": "https://github.com/lionsoul2016/ip2region" "homepage": "https://github.com/lionsoul2016/ip2region",
"devDependencies": {
"jest": "^19.0.2"
}
} }

View File

@ -1,15 +0,0 @@
/**
* test program
* */
var Ip2region = require('./ip2region');
// 1. create a ip2region object
var ipObj = Ip2region.create('../../data/ip2region.db');
// 2. use
//console.log(ipObj.binarySearchSync("120.24.78.68"));
console.log(ipObj.btreeSearchSync("120.24.78.68"));
// 3. destroy
Ip2region.destroy(ipObj);

1979
binding/nodejs/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
*/ */
defined('INDEX_BLOCK_LENGTH') or define('INDEX_BLOCK_LENGTH', 12); defined('INDEX_BLOCK_LENGTH') or define('INDEX_BLOCK_LENGTH', 12);
defined('TOTAL_HEADER_LENGTH') or define('TOTAL_HEADER_LENGTH', 4096); defined('TOTAL_HEADER_LENGTH') or define('TOTAL_HEADER_LENGTH', 8192);
class Ip2Region class Ip2Region
{ {

View File

@ -110,7 +110,7 @@ class Ip2Region(object):
#pass the super block #pass the super block
self.__f.seek(8) self.__f.seek(8)
#read the header block #read the header block
b = self.__f.read(4086) b = self.__f.read(8192)
#parse the header block #parse the header block
sip = None sip = None
ptr = None ptr = None

View File

@ -15,7 +15,7 @@ def testSearch():
llen = len(sys.argv) llen = len(sys.argv)
if llen < 2: if llen < 2:
print "Usage: python ip2Region.py [ip2region db file] [alrogrithm]" print "Usage: python testSearcher.py [ip2region db file] [alrogrithm]"
print "Algorithm: binary or b-tree" print "Algorithm: binary or b-tree"
return 0 return 0

View File

@ -0,0 +1,240 @@
#-*- coding:utf-8 -*-
"""
" ip2region python seacher client module
"
" Author: koma<komazhang@foxmail.com>
" Date : 2015-11-06
"""
import struct, io, socket, sys
class Ip2Region(object):
__headerSip = []
__headerPtr = []
__f = None
__sPtr = 0
__indexLen = 0
__dbBinStr = ''
def __init__(self, dbfile):
self.initDatabase(dbfile)
def memorySearch(self, ip):
"""
" memory search method
" param: ip
"""
if not ip.isdigit(): ip = self.ip2long(ip)
if self.__dbBinStr == '':
self.__dbBinStr = self.__f.read() #read all the contents in file
self.__sPtr = self.getLong(self.__dbBinStr, 0)
endPtr = self.getLong(self.__dbBinStr, 4)
self.__indexLen = endPtr - self.__sPtr
startPtr = self.__sPtr
indexLen = self.__indexLen
dbBinStr = self.__dbBinStr
l, h, mixPtr = (0, int(indexLen/12), 0)
while l <= h:
m = int((l+h)/2)
ptr = startPtr + m*12
sip = self.getLong(dbBinStr, ptr)
eip = self.getLong(dbBinStr, ptr+4)
if ip >= sip:
if ip > eip:
l = m + 1
else:
mixPtr = self.getLong(dbBinStr, ptr+8)
break;
else:
h = m - 1
if mixPtr == 0: return "N2"
return self.returnData(mixPtr)
def binarySearch(self, ip):
"""
" binary search method
" param: ip
"""
if not ip.isdigit(): ip = self.ip2long(ip)
if self.__indexLen < 1:
self.__f.seek(0)
b = self.__f.read(8)
self.__sPtr = self.getLong(b, 0)
endPtr = self.getLong(b, 4)
self.__indexLen = endPtr - self.__sPtr
startPtr = self.__sPtr
indexLen = self.__indexLen
self.__f.seek(startPtr)
b = self.__f.read(indexLen+12)
l, h, mixPtr = (0, int(indexLen/12), 0)
while l <= h:
m = int((l+h)/2)
ptr = startPtr + m*12
self.__f.seek(ptr)
b = self.__f.read(12)
sip = self.getLong(b, 0)
eip = self.getLong(b, 4)
if ip >= sip:
if ip > eip:
l = m + 1
else:
mixPtr = self.getLong(b, 8)
break;
else:
h = m - 1
if mixPtr == 0: return "N2"
return self.returnData(mixPtr)
def btreeSearch(self, ip):
"""
" b-tree search method
" param: ip
"""
if not ip.isdigit(): ip = self.ip2long(ip)
if len(self.__headerSip) < 1:
#pass the super block
self.__f.seek(8)
#read the header block
b = self.__f.read(8192)
#parse the header block
sip = None
ptr = None
for i in range(0, len(b)-1, 8):
sip = self.getLong(b, i)
ptr = self.getLong(b, i+4)
if ptr == 0:
break
self.__headerSip.append(sip)
self.__headerPtr.append(ptr)
headerLen = len(self.__headerSip) - 1
l, h, sptr, eptr = (0, headerLen, 0, 0)
while l <= h:
m = int((l+h)/2)
if ip == self.__headerSip[m]:
if m > 0:
sptr = self.__headerPtr[m-1]
eptr = self.__headerPtr[m]
break;
else:
sptr = self.__headerPtr[m]
eptr = self.__headerPtr[m+1]
break;
if ip > self.__headerSip[m]:
if m == headerLen:
sptr = self.__headerPtr[m-1]
eptr = self.__headerPtr[m]
break;
elif ip < self.__headerSip[m+1]:
sptr = self.__headerPtr[m]
eptr = self.__headerPtr[m+1]
break;
l = m + 1
else:
if m == 0:
sptr = self.__headerPtr[m]
eptr = self.__headerPtr[m+1]
break;
elif ip > self.__headerSip[m-1]:
sptr = self.__headerPtr[m-1]
eptr = self.__headerPtr[m]
break;
h = m - 1
if sptr == 0: return "N1"
indexLen = eptr - sptr
self.__f.seek(sptr)
b = self.__f.read(indexLen + 12)
l, h, mixPtr = (0, int(indexLen/12), 0)
while l <= h:
m = int((l+h)/2)
offset = m * 12
if ip >= self.getLong(b, offset):
if ip > self.getLong(b, offset+4):
l = m + 1
else:
mixPtr = self.getLong(b, offset+8)
break;
else:
h = m - 1
if mixPtr == 0: return "N2"
return self.returnData(mixPtr)
def initDatabase(self, dbfile):
"""
" initialize the database for search
" param: dbFile
"""
try:
self.__f = io.open(dbfile, "rb")
except IOError as e:
print ("[Error]: ", e)
sys.exit()
def returnData(self, dsptr):
"""
" get ip data from db file by data start ptr
" param: dsptr
"""
dataPtr = dsptr & 0x00FFFFFF
dataLen = (dsptr >> 24) & 0xFF
self.__f.seek(dataPtr)
data = self.__f.read(dataLen)
return {
"city_id": self.getLong(data, 0),
"region" : data[4:]
}
def ip2long(self, ip):
_ip = socket.inet_aton(ip)
return struct.unpack("!L", _ip)[0]
def isip(self, ip):
p = ip.split(".")
if len(p) != 4 : return False
for pp in p:
if not pp.isdigit() : return False
if len(pp) > 3 : return False
if int(pp) > 255 : return False
return True
def getLong(self, b, offset):
if len( b[offset:offset+4] ) == 4:
return struct.unpack('I', b[offset:offset+4])[0]
return 0
def close(self):
self.__headerSip = None
self.__headerPtr = None
self.__f.close()
self.__f = None

View File

@ -0,0 +1,79 @@
#-*- coding:utf-8 -*-
"""
" ip2region python seacher client module
"
" Autho: koma<komazhang@foxmail.com>
" Date : 2015-11-06
"""
import struct, sys, os, time
from ip2Region import Ip2Region
def testSearch():
"""
" ip2region test function
"""
llen = len(sys.argv)
if llen < 2:
print ("Usage: python testSearcher.py [ip2region db file] [alrogrithm]")
print ("Algorithm: binary or b-tree")
return 0
dbFile = sys.argv[1]
method = 1
algorithm = "b-tree"
if (not os.path.isfile(dbFile)) or (not os.path.exists(dbFile)):
print ("[Error]: Specified db file is not exists.")
return 0
if llen > 2:
algorithm = sys.argv[2]
if algorithm == "binary":
method = 2
elif algorithm == "memory":
method = 3
print ("initializing %s..."% algorithm)
print ("+----------------------------------+")
print ("| ip2region test program |")
print ("| Author: chenxin619315@gmail.com. |")
print ("| Type 'quit' or 'exit' to exit program |")
print ("+----------------------------------+")
searcher = Ip2Region(dbFile);
while True:
line = input("ip2region>> ")
line = line.strip()
if line == "":
print ("[Error]: Invalid ip address.")
continue
if line == "quit" or line == "exit" :
print ("[Info]: Thanks for your use, Bye.")
break
if not searcher.isip(line):
print ("[Error]: Invalid ip address.")
continue
sTime = time.time() * 1000
if method == 1:
data = searcher.btreeSearch(line)
elif method == 2:
data = searcher.binarySearch(line)
else:
data = searcher.memorySearch(line)
eTime = time.time() * 1000
if isinstance(data, dict):
print ("%s|%s in %f millseconds" % (data["city_id"], data["region"].decode('utf-8'), eTime-sTime))
else:
print ("[Error]: ", data)
searcher.close()
if __name__ == "__main__":
testSearch()

File diff suppressed because it is too large Load Diff

Binary file not shown.

BIN
dbMaker-1.2.2.jar Normal file

Binary file not shown.