获取免费IP地址的算法

时间:2017-04-13 16:11:59

标签: php mysql algorithm optimization yii2

我使用yii2。我需要通过方法getFreeIPAddress找到未使用的IP(不在数据库中)。我有这样的课:

class Radreply extends ActiveRecord {

   const ATTRIBUTE_DEFAULT_IP_ADDRESS = 'Framed-IP-Address';

   const IP_ADDRESS_MAX = '10.255.255.255';  // max value for IP 
   const IP_ADDRESS_MIN = '10.0.0.11';       // min value for IP

   public function getIntegerIP(){  // converts IP from string to integer format
       return ip2long($this->value);
   }

   public static function getFreeIPAddress(){
        $records = self::findAll(['attribute'=>self::ATTRIBUTE_DEFAULT_IP_ADDRESS]); // get all record which contain IP address
        $existIPs = ArrayHelper::getColumn($records,'integerIP'); // get array of IP which is converted to integer by method getIntegerIP

        for ($integerIP = ip2long(self::IP_ADDRESS_MIN); $integerIP<=ip2long(self::IP_ADDRESS_MAX); $integerIP++){
        // increasing one by one IP address in integer format from value IP_ADDRESS_MIN to value IP_ADDRESS_MAX

            if (!in_array($integerIP, $existIPs)){
                $stringIP = long2ip($integerIP);
                $arrayDigits = explode('.', $stringIP);
                $lastDigit = array_pop($arrayDigits);

                if ($lastDigit!='0'){ // check if last digit of IP is not 0
                    return $stringIP;
                }

            }

        }
        return '';
    }
}

方法getFreeIPAddress工作find,但是在db中有很多带IP的记录并逐个增加IP并检查db中是否存在这个IP是非常漫长的。我如何优化此算法?是否有更快的方式来获取未使用的IP?

2 个答案:

答案 0 :(得分:1)

我想,我已经找到了更好的解决方案而没有数据库中的额外表格

class Radreply extends ActiveRecord {

  const ATTRIBUTE_DEFAULT_IP_ADDRESS = 'Framed-IP-Address';

  const IP_ADDRESS_MAX = '10.255.255.255';  // max value for IP 
  const IP_ADDRESS_MIN = '10.0.0.11';       // min value for IP

  public function getIntegerIP(){  // converts IP from string to integer format
      return ip2long($this->value);
  }

    public static function getFreeIPAddress(){
        $records = self::findAll(['attribute'=>self::ATTRIBUTE_DEFAULT_IP_ADDRESS]); // gets all record which contain IP address
        $existIPs = ArrayHelper::getColumn($records,'integerIP'); // gets array of IP which is converted to integer by method getIntegerIP

        $intIpAddressMin = ip2long(self::IP_ADDRESS_MIN);     // gets min IP in integer format
        $endRange = empty($existIPs) ? $intIpAddressMin : max($existIPs);  // checks if at least one IP is used
        $availableIPs = range( $intIpAddressMin, $endRange + 2);   // generates array with available IP addresses (+2 because next address can be with last digit 0)
        $missingIPs = array_diff($availableIPs,$existIPs);  // removes all used IP

        foreach ($missingIPs as $value){
            $lastDigit = $value % 256;
            if ($lastDigit != 0){
                return long2ip($value);
            }
        }
        return '';
    }
}

答案 1 :(得分:0)

  

bool in_array(混合$ needle,数组$ haystack [,bool $ strict = FALSE])

在我看来,你可以设置严格的真实。

我的php代码 strict = false

xhr.addEventListener('error', (err: Event) => {

时间php test.php

<?php                                                                                                                                                            

 $y="1800";
 $x = array();
 for($j=0;$j<50000;$j++){
        $x[]= "{$j}";
 }

 for($i=0;$i<30000;$i++){
    if(in_array($y,$x)){
            continue; 
     }
  }

当strict为 true

real    0m4.418s
user    0m4.404s
 sys    0m0.012s

时间php test.php

for($i=0;$i<30000;$i++){
    if(in_array($y,$x ,true)){
              continue;
       }
 }

更重要的是,如果你能按升序获得使用过的ip。你可以得到 o(m + n)时间复杂度,m是你应该尝试的所有ip的长度,n是db中所有ip的长度,合并算法

如果您可以按升序获取已使用的IP

Pseudocode中的

 real   0m1.548s
 user   0m1.540s
 sys    0m0.004s

这是我的PHP代码,其中我通过$ count ++重新生成echo ip; 在此演示中,大约有80000个ip,类型为

tmpIp = minIp;
while(temIp <= maxIp){
         if( dbIsEmpty){
             break;
         }
            dbIp =getNextFromDb();

        while(temIp < dbIp){
         printf temIp ;
         temIp ++;
        }
        temIp ++;
 }
while(temIp <= maxIp){
    printf temIp ;
    temIp++;
}
这需要大约10秒;     时间php test.php       184460881      真正的0m10.626s      用户0m10.416s      sys 0m0.168s