Lua binding completed(tested)
This commit is contained in:
parent
5f073d814e
commit
86ad8057aa
|
|
@ -18,7 +18,7 @@ ip2region - 最自由的ip地址查询库,ip到地区的映射库,提供Bina
|
|||
|
||||
### 4. 多查询客户端的支持,0.0x毫秒级别的查询
|
||||
|
||||
已经集成的客户端有:java, C#, php, c, python,nodejs,php扩展(支持linux, php5, php7版本已支持),golang。
|
||||
已经集成的客户端有:java、C#、php、c、python、nodejs、php扩展(php5和php7)、golang、rust、lua。
|
||||
|
||||
提供了两种查询算法,响应时间如下:
|
||||
客户端/binary算法/b-tree算法/Memory算法:
|
||||
|
|
@ -27,6 +27,7 @@ ip2region - 最自由的ip地址查询库,ip到地区的映射库,提供Bina
|
|||
php/0.x毫秒/0.1x毫秒/0.1x毫秒
|
||||
c/0.0x毫秒/0.0x毫秒/0.00x毫秒(b-tree算法基本稳定在0.02x毫秒级别)
|
||||
python/0.x毫秒/0.1x毫秒/未知
|
||||
lua/0.x毫秒/0.x毫秒/0.x毫秒
|
||||
|
||||
任何客户端b-tree都比binary算法快,当然Memory算法固然是最快的!
|
||||
|
||||
|
|
@ -70,6 +71,12 @@ python:
|
|||
python binding/python/testSearcher.py ./data/ip2region.db
|
||||
```
|
||||
|
||||
lua:
|
||||
```shell
|
||||
cd binding/lua/
|
||||
lua testSearcher.lua ../../data/ip2region.db
|
||||
```
|
||||
|
||||
均会看到如下界面:
|
||||
```shell
|
||||
initializing B-tree ...
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Ip2region lua binding
|
||||
_M lua binding
|
||||
|
||||
@author chenxin<chenxin619315@gmail.com>
|
||||
@date 2018/10/02
|
||||
|
|
@ -7,23 +7,22 @@ Ip2region lua binding
|
|||
|
||||
require("bit32");
|
||||
|
||||
local Ip2region = {
|
||||
local INDEX_BLOCK_LENGTH = 12;
|
||||
local TOTAL_HEADER_LENGTH = 8192;
|
||||
local _M = {
|
||||
dbFile = "",
|
||||
dbFileHandler = "",
|
||||
dbFileHandler = nil,
|
||||
dbBinStr = "",
|
||||
HeaderSip = "",
|
||||
HeaderPtr = "",
|
||||
headerLen = "",
|
||||
HeaderSip = nil,
|
||||
HeaderPtr = nil,
|
||||
headerLen = 0,
|
||||
firstIndexPtr = 0,
|
||||
lastIndexPtr = 0,
|
||||
totalBlocks = 0
|
||||
};
|
||||
|
||||
|
||||
-- common constants
|
||||
local INDEX_BLOCK_LENGTH = 12;
|
||||
local TOTAL_HEADER_LENGTH = 8192;
|
||||
function Ip2region:new(obj)
|
||||
_G["Ip2region"] = _M;
|
||||
function _M:new(obj)
|
||||
obj = obj or {};
|
||||
setmetatable(obj, {__index = self});
|
||||
return obj;
|
||||
|
|
@ -58,27 +57,37 @@ internal function to convert the string ip to a long value
|
|||
@param ip
|
||||
@return Integer
|
||||
]]--
|
||||
function ip2long(ip)
|
||||
function _M:ip2long(ip)
|
||||
local ini = 1;
|
||||
local iip = 0;
|
||||
local off = 24;
|
||||
local int = 0;
|
||||
while true do
|
||||
local pos = string.find(ip, '.', ini, true);
|
||||
if ( not pos or off <= 0 ) then
|
||||
if ( not pos ) then
|
||||
break;
|
||||
end
|
||||
|
||||
int = tonumber(string.sub(ip, ini, pos - 1));
|
||||
iip = bit32.bor(iip, bit32.lshift(int, off));
|
||||
local sub = string.sub(ip, ini, pos - 1);
|
||||
if ( string.len(sub) < 1 ) then
|
||||
return nil;
|
||||
end
|
||||
|
||||
iip = bit32.bor(iip, bit32.lshift(tonumber(sub), off));
|
||||
ini = pos + 1;
|
||||
off = off - 8;
|
||||
end
|
||||
|
||||
int = tonumber(string.sub(ip, ini));
|
||||
iip = bit32.bor(iip, bit32.lshift(int, off));
|
||||
-- check if it is a valid ip address
|
||||
if ( off ~= 0 or ini > string.len(ip) ) then
|
||||
return nil;
|
||||
end
|
||||
|
||||
return iip;
|
||||
local sub = string.sub(ip, ini);
|
||||
if ( string.len(sub) < 1 ) then
|
||||
return nil;
|
||||
end
|
||||
|
||||
return bit32.bor(iip, bit32.lshift(tonumber(sub), off));
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -108,7 +117,15 @@ then search the memory only and this will a lot faster than disk base search
|
|||
@param ip
|
||||
@return table or nil for failed
|
||||
]]--
|
||||
function Ip2region:memorySearch(ip)
|
||||
function _M:memorySearch(ip)
|
||||
-- string ip conversion
|
||||
if ( type(ip) == "string" ) then
|
||||
ip = self:ip2long(ip);
|
||||
if ( ip == nil ) then
|
||||
return nil;
|
||||
end
|
||||
end;
|
||||
|
||||
-- check and load the binary string for the first time
|
||||
if ( self.dbBinStr == "" ) then
|
||||
self.dbBinStr = get_file_contents(self.dbFile);
|
||||
|
|
@ -121,9 +138,6 @@ function Ip2region:memorySearch(ip)
|
|||
self.totalBlocks = (self.lastIndexPtr - self.firstIndexPtr)/INDEX_BLOCK_LENGTH + 1;
|
||||
end
|
||||
|
||||
if ( type(ip) == "string" ) then
|
||||
ip = ip2long(ip);
|
||||
end;
|
||||
|
||||
-- binary search to define the data
|
||||
local l = 0;
|
||||
|
|
@ -168,15 +182,18 @@ or long ip numeric with binary search algorithm
|
|||
@param ip
|
||||
@return table or nil for failed
|
||||
]]--
|
||||
function Ip2region:binarySearch(ip)
|
||||
function _M:binarySearch(ip)
|
||||
-- check and conver the ip address
|
||||
if ( type(ip) == "string" ) then
|
||||
ip = ip2long(ip);
|
||||
ip = self:ip2long(ip);
|
||||
if ( ip == nil ) then
|
||||
return nil;
|
||||
end
|
||||
end
|
||||
|
||||
if ( self.totalBlocks == 0 ) then
|
||||
-- check and open the original db file
|
||||
if ( self.dbFileHandler == "" ) then
|
||||
if ( self.dbFileHandler == nil ) then
|
||||
self.dbFileHandler = io.open(self.dbFile, "r");
|
||||
if ( not self.dbFileHandler ) then
|
||||
return nil;
|
||||
|
|
@ -239,15 +256,19 @@ get the data block associated with the specified ip with b-tree search algorithm
|
|||
@param ip
|
||||
@return table or nil for failed
|
||||
]]--
|
||||
function Ip2region:btreeSearch(ip)
|
||||
if ( type(ip) ) then
|
||||
ip = ip2long(ip);
|
||||
function _M:btreeSearch(ip)
|
||||
-- string ip to integer conversion
|
||||
if ( type(ip) == "string" ) then
|
||||
ip = self:ip2long(ip);
|
||||
if ( ip == nil ) then
|
||||
return nil;
|
||||
end
|
||||
end
|
||||
|
||||
-- check and load the header
|
||||
if ( self.HeaderSip == "" ) then
|
||||
if ( self.headerLen == 0 ) then
|
||||
-- check and open the original db file
|
||||
if ( self.dbFileHandler == "" ) then
|
||||
if ( self.dbFileHandler == nil ) then
|
||||
self.dbFileHandler = io.open(self.dbFile, 'r');
|
||||
if ( not self.dbFileHandler ) then
|
||||
return nil;
|
||||
|
|
@ -277,6 +298,7 @@ function Ip2region:btreeSearch(ip)
|
|||
self.headerLen = idx;
|
||||
end
|
||||
|
||||
|
||||
-- 1. define the index block with the binary search
|
||||
local l = 0;
|
||||
local h = self.headerLen;
|
||||
|
|
@ -368,4 +390,4 @@ function Ip2region:btreeSearch(ip)
|
|||
end
|
||||
|
||||
|
||||
return Ip2region;
|
||||
return _M;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
# Lua ip2region binding
|
||||
|
||||
### 一,如何测试
|
||||
* 1, cd到ip2region/binding/lua/根目录
|
||||
* 2, 运行testSearcher测试程序
|
||||
```shell
|
||||
lua testSearcher.lua ../../data/ip2region.db
|
||||
```
|
||||
* 3, 输入ip地址开始测试即可
|
||||
```shell
|
||||
initializing btree
|
||||
+----------------------------------+
|
||||
| ip2region test script |
|
||||
| Author: chenxin619315@gmail.com |
|
||||
| Type 'quit' to exit program |
|
||||
+----------------------------------+
|
||||
ip2region>> 1.2.3.4
|
||||
0|美国|0|华盛顿|0|0 in 8.001000 millseconds
|
||||
ip2region>> 101.233.153.103
|
||||
2163|中国|0|广东省|深圳市|鹏博士 in 0.176000 millseconds
|
||||
ip2region>>
|
||||
```
|
||||
|
||||
|
||||
### 二,如何使用
|
||||
* 1, 将Ip2region.lua拷贝到你的package.path下
|
||||
* 2, 通过如下流程在你的lua程序中使用
|
||||
```lua
|
||||
-- 包含模块
|
||||
require "Ip2region";
|
||||
|
||||
-- 创建查询对象
|
||||
-- dbFile表示ip2region.db数据库文件的地址
|
||||
local searcher = Ip2region:new({dbFile: "ip2region.db file path"});
|
||||
local data;
|
||||
|
||||
-- 查询,备注请使用“:”调用方法,不要使用“.”
|
||||
-- 1,binary查询
|
||||
data = searcher:binarySearch("101.233.153.103");
|
||||
|
||||
-- 2,btree查询
|
||||
data = searcher:btreeSearch("101.233.153.103");
|
||||
|
||||
-- 3,memory查询
|
||||
data = searcher:memorySearch("101.233.153.103");
|
||||
|
||||
-- 返回结果如下
|
||||
print("city_id=", data.city_id, "region=", data.region);
|
||||
```
|
||||
|
|
@ -1,9 +1,74 @@
|
|||
-- ip2region test lua script
|
||||
local cjson = require "cjson";
|
||||
local Ip2region = require "Ip2region";
|
||||
--[[
|
||||
ip2region lua client test script
|
||||
|
||||
@author chenxin<chenxin619315@gmail.com>
|
||||
]]--
|
||||
|
||||
-- check the command line arguments
|
||||
if ( not arg[1] ) then
|
||||
print([[
|
||||
Usage: lua testSearcher.lua [ip2region db file] [algorithm]
|
||||
+-Optional Algorithm: binary, b-tree, memory]]);
|
||||
os.exit();
|
||||
end
|
||||
|
||||
local Ip2region = require "Ip2region";
|
||||
-- local cjson = require "cjson";
|
||||
-- local socket = require "socket";
|
||||
|
||||
|
||||
-- check and parse the dbFile and the method algorithm
|
||||
local searcher = Ip2region:new({dbFile = arg[1]});
|
||||
local algorithm = "btree";
|
||||
if ( arg[2] ~= nil ) then
|
||||
local arg_2 = string.lower(arg[2]);
|
||||
if ( arg_2 ~= "binary" and arg_2 ~= "memory" ) then
|
||||
algorithm = "binary";
|
||||
elseif ( arg_2 == "memory" ) then
|
||||
algorithm = "memory";
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local searcher = Ip2region:new({dbFile = "../../data/ip2region.db"});
|
||||
-- local data = searcher:memorySearch("120.79.17.142");
|
||||
-- local data = searcher:binarySearch("120.79.17.142");
|
||||
local data = searcher:btreeSearch("120.79.17.142");
|
||||
print(cjson.encode(data));
|
||||
-- local data = searcher:btreeSearch("120.79.17.142");
|
||||
print("initializing " .. algorithm ..[[
|
||||
+----------------------------------+
|
||||
| ip2region test script |
|
||||
| Author: chenxin619315@gmail.com |
|
||||
| Type 'quit' to exit program |
|
||||
+----------------------------------+]]
|
||||
);
|
||||
|
||||
while ( true ) do
|
||||
io.write("ip2region>> ");
|
||||
io.input(io.stdin);
|
||||
local line = io.read();
|
||||
if ( line == nil ) then
|
||||
-- do nothing
|
||||
break;
|
||||
elseif ( line == "quit" ) then
|
||||
break;
|
||||
elseif ( searcher:ip2long(line) == nil ) then
|
||||
print("Invalid ip address=", line);
|
||||
else
|
||||
local data;
|
||||
local s_time = os.clock();
|
||||
if ( algorithm == "btree" ) then
|
||||
data = searcher:btreeSearch(line);
|
||||
elseif ( algorithm == "binary" ) then
|
||||
data = searcher:binarySearch(line);
|
||||
elseif ( algorithm == "memory" ) then
|
||||
data = searcher:memorySearch(line);
|
||||
end
|
||||
|
||||
local cost_time = (os.clock() - s_time) * 1000; -- to millseconds
|
||||
if ( data == nil ) then
|
||||
io.write("Failed for ip=", line, " is it a valid ip address ?");
|
||||
else
|
||||
io.write(string.format("%u|%s in %5f millseconds\n", data.city_id, data.region, cost_time));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
if ( $argc < 2 ) {
|
||||
$usage = <<<EOF
|
||||
Usage: php Test.php [ip2region db file] [alrogrithm]
|
||||
+-Algorithm: binary or b-tree\n
|
||||
+-Optional Algorithm: binary, b-tree, memory\n
|
||||
EOF;
|
||||
exit($usage);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue