commit
e4f54054c4
|
|
@ -6,6 +6,7 @@
|
||||||
META-INF/
|
META-INF/
|
||||||
# Binary Files #
|
# Binary Files #
|
||||||
*.jar
|
*.jar
|
||||||
|
!dbMaker-*.jar
|
||||||
# Package Files #
|
# Package Files #
|
||||||
.settings/
|
.settings/
|
||||||
.classpath
|
.classpath
|
||||||
|
|
|
||||||
31
CHANGES.md
31
CHANGES.md
|
|
@ -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,修复原始数据关于“香港,台湾,澳门”国家信息错误的bug,reported 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定位错误!
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
28
README.md
28
README.md
|
|
@ -18,7 +18,7 @@ ip2region - 最自由的ip地址查询库,ip到地区的映射库,提供Bina
|
||||||
|
|
||||||
**4. 多查询客户端的支持,0.0x毫秒级别的查询**
|
**4. 多查询客户端的支持,0.0x毫秒级别的查询**
|
||||||
|
|
||||||
已经集成的客户端有:java, php, c, python,nodejs,php扩展(支持linux, php5, php7版本已支持)。
|
已经集成的客户端有:java, php, c, python,nodejs,php扩展(支持linux, php5, php7版本已支持),golang。
|
||||||
|
|
||||||
提供了两种查询算法,响应时间如下:
|
提供了两种查询算法,响应时间如下:
|
||||||
客户端/binary算法/b-tree算法/Memory算法:
|
客户端/binary算法/b-tree算法/Memory算法:
|
||||||
|
|
@ -64,3 +64,29 @@ python:
|
||||||
输入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/tools/2016/08/18/structure-of-ip2region-database-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;
|
||||||
|
}
|
||||||
|
|
@ -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 4096
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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*/
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules/
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
# nodejs 客户端
|
# nodejs 客户端
|
||||||
|
|
||||||
现已实现同步查询,异步查询未实现,用法参考 test.js
|
现已实现同步查询,异步查询未实现,用法参考 ip2region.spec.js
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
@ -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();
|
||||||
|
});
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
File diff suppressed because it is too large
Load Diff
41187
data/ip.merge.txt
41187
data/ip.merge.txt
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue