判斷一個IP是否歸屬於中國


業務的要求

  • 判斷一個IP是不是屬於中國的
  • 時間復雜度盡量小,適用於請求量大的業務場景
  • 不要請求第三方接口,防止出現網絡異常

由於只需要判斷到國家的緯度,所以不需要用到純真IP庫這樣龐大的IP庫,通過網上的查詢,發現有個中國IP段的列表
http://ipblock.chacuo.net/down/t_txt=c_CN
可以看到IP段有2K個左右,如果用二分查詢法,時間復雜度是logN。基本上能夠滿足需求了。

實現步驟

一、 整理IP段配置

為了方便IP進行比較,這里將IP轉換為long格式。

  1. 把數據load進來,取第一第二行,ip2long處理
  2. 第一行保存在left,第二行保存在right中
  3. 然后根據left進行排序

最終得到的結果,如下:

<?php
#部分數據
array (
  0 => 
  array (
    'left' => '16777472',
    'right' => '16778239',
  ),
  1 => 
  array (
    'left' => '16779264',
    'right' => '16781311',
  ),
  2 => 
  array (
    'left' => '16785408',
    'right' => '16793599',
  ),
  3 => 
  array (
    'left' => '16842752',
    'right' => '16843007',
  ),
  4 => 
  array (
    'left' => '16843264',
    'right' => '16859135',
  )
);

二、二分查找法

function binarySearch(Array $arr, $target) {
    $low = 0;
    $high = count($arr) - 1;
    while($low <= $high) {
        $mid = floor(($low + $high) / 2);
        #找到元素
        if($target>=$arr[$mid]['left'] && $target<=$arr[$mid]['right']){
            return true;
        }
        #中元素比目標大,查找左部
        if($target < $arr[$mid]['left'] ){
            $high = $mid - 1;
        }
        #中元素比目標小,查找右部
        if($target > $arr[$mid]['left'] ){
            $low = $mid + 1;
        }
    }
    #查找失敗
    return false;
}

bitmap算法是否可行?

ip地址轉為long的最大值剛好是2^32-1 ,那么在redis中我們剛好可以申請一個4294967295的bitmap,占用內存為512M。
如果能夠把所有中國的IP對應的long都設置為1,那么每次查詢都只要0(1),遇到的問題是redis的setbit怎么批量設置呢?如果要一個ip設置一次的話,需要設置3億次,這個比較難實現。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM