将IPv4地址拆分为最小和最大范围。

使用Lua如何拆分给定的IP地址,以获取最小和最大范围,例如:

94.19.21.119

我有一个像这样的CSV:

18087936,18153471,“AU”
18153472,18219007,“JP”
18219008,18350079,“IN”
18350080,18874367,“CN”

已读取为3个表并且csv是min,max,country code:

IPfrom = {}
IPto = {}
IPCountry = {}

它们像这样被填充:

IPfrom [18087936] = L
IPto [L] = 18153471
IPCountry [L] =“AU”

其中L是io.read的行号,然后我尝试获取最小范围,以便我可以在不循环的情况下检查是否存在,然后如果它存在,该键将保存最大范围的索引,如果IP在最小/最大范围内,那么我获取国家代码。可能有一种不同的做事方式,但表中有超过100,000个条目,因此循环需要一些时间。

点赞
用户142162
用户142162

也许以下代码对你有用:

--
-- 将IPv4地址转化为整数值
--
function iptoint(ip)
    local ipint = 0
    local iter = string.gmatch(ip, "%d+")
    for i = 3, 0, -1 do
        local piece = tonumber(iter())
        if piece == nil or piece < 0 or piece > 255 then
            return nil
        end
        ipint = bit32.bor(ipint, bit32.lshift(piece, 8 * i))
    end
    return ipint
end

--
-- 在一个多维表中查找IPv4地址,表中的条目为:
-- {start_address, end_address, country}
-- 然后返回匹配的国家
--
function iptocountry(ip, tbl)
    local ipint = iptoint(ip)
    if ipint == nil then
        return nil
    end
    for _,v in pairs(tbl) do
        if ipint >= v[1] and ipint <= v[2] then
            return v[3]
        end
    end
    return nil
end

用法示例:

local countries = {
    {16777216, 17367039, "US"},
    {1578300000, 1678300000, "CAN"}
    -- ... 从CSV文件中加载其他条目
}

local ip = "94.19.21.119"
print (iptocountry(ip, countries)) -- 输出CAN
2014-02-11 14:16:52
用户869951
用户869951

哈希表(Lua的基本类型)会给你 O(N) 的时间复杂度。没有空洞且索引从 someMinAddr 到 someMaxAddr 的数组(一种表)会给你 O(1) 的时间复杂度,但会使用相当多的内存。通过适当地排序结构化表进行二分查找,可以给你 O(log N) 的时间复杂度,对于 100000 个地址来说,这可能值得付出努力。我想你可以使用这样的结构:

IPfrom = {
    {line=L1, addFrom=from1, addrTo=to1, c=country1},
    {line=L2, addFrom=from2, addrTo=to2, c=country2},
    {line=L3, addFrom=from3, addrTo=to3, c=country3},
    {line=L4, addFrom=from4, addrTo=to4, c=country4},
    ...
}

因为我没看到将to和country字段与其他信息分开的意义,这只会增加表查找的次数。无论如何,如果你真的想把它们分开,下面的代码不会受到影响:

-- 初始化:
从 CSV 文件创建表
对 IPFrom 中的 addFrom 字段进行排序

-- 需要多少次就执行多少次:
function findIP(addr)
    addr 是否小于 IPfrom[middle].addrTo3?
    如果是,addr 是否小于 IPfrom[middle of middle]?
        等等
end

这是递归的,所以如果你将其结构化得当,可以使用尾递归,并不担心栈溢出 (;),类似这样:

function findIPRecurs(addr, ipTbl, indxMin, indxMax)
    local middle = (indxMin + indxMax )/2
    local midAddr = ipTbl[middle].addrFrom
    if addr < midAddr then
        return findIPRecurs(addr, ipTbl, indxMin, middle)
    else if addr > midAddr then
        return findIPRecurs(addr, ipTbl, middle, indxMax)
    else -- 有条目:
        return middle
    end
end

function findIP(addr)
    return findIPRecurs(addr, ipTbl, 1, #ipTbl)
end

我没有测试过,所以可能还需要修整,但你可以理解这个思路。这将使用与 O(N) 方法相同的内存,但对于大型数组来说,速度会快得多;比 O(1) 方法少得多的内存,并且可能可以接受更慢的速度。

2014-02-11 21:09:10