Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 获取免费IP地址的算法_Php_Mysql_Algorithm_Optimization_Yii2 - Fatal编程技术网

Php 获取免费IP地址的算法

Php 获取免费IP地址的算法,php,mysql,algorithm,optimization,yii2,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

我使用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可以找到,但是在db中有很多IP记录,并且一个接一个地增加IP,检查db中是否存在这个IP还有很长的路要走。如何优化这个算法?有没有更快的方法获取未使用的IP

bool in_数组混合$needle,数组$haystack[,bool$strict=FALSE]

在我看来,你可以设定严格的真实性

我的php代码带有strict=false

当严格是真的

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

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

在伪代码中

这是我的php代码,其中我用$count++重新封装了EchoIP; 在这个演示中,大约有80000个ip,类型为long

大约需要10秒; time php test.php 184460881 实际0m10.626s 用户0m10.416s
sys 0m0.168s

我想,我已经找到了更好的解决方案,而不需要在数据库中添加额外的表

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 '';
    }
}

嗯,您可以创建一个包含所有可用IP地址的表,然后右键连接到另一个表以获得免费IP的列表addresses@cmorrissey谢谢,好主意。但如果我想更改可用IP地址的范围,就会出现问题,每次我都需要创建新表。此外,这个表将非常大:最小值-10.0.0.11',最大值-10.255.255'16 777 204条记录。我有一个新想法给你。。。在一个IP地址范围内计算数据库中的行数,如果不转到下一个范围,则查看是否有可用的IP地址,并且可以递归地缩小范围。这是一个非常基本的搜索函数,但它应该以指数方式加快搜索速度。@cmorrissey我不明白你的真正意思。你能详细描述一下吗?但无论如何,谢谢,计数这是个好主意,我认为计数是该算法优化的关键。按照@cmorrissey的建议,创建一个可用IP地址表。所以,如果它很大,有1600万行,它仍然是16兆字节+SQL数据库的任何开销。此外,如果需要向池中添加更多地址,则无需创建新表,只需向该表中插入更多行即可!此外,如果您使用的是MySQL,您可能希望使用INET_ATON和INET_NTOA在查询中转换整数。不过,不要加入,只要在地址用完时删除地址即可。谢谢你的回答。你所说的合并算法是什么意思?我有一个问题,你只需要一个未使用的ip,或者一次性获得所有未使用的ip?只有一个未使用的ip地址你可以得到10000个未使用的ip地址,并通过合并算法保存到新表中。当您想要一个未使用的ip时,您只需从这个新表中获取ip,并向使用过的旧表中添加一行即可。每次新表为空时,使用合并算法获得新的10000行。您能看看我的新解决方案吗?
real    0m4.418s
user    0m4.404s
 sys    0m0.012s
for($i=0;$i<30000;$i++){
    if(in_array($y,$x ,true)){
              continue;
       }
 }
 real   0m1.548s
 user   0m1.540s
 sys    0m0.004s
tmpIp = minIp;
while(temIp <= maxIp){
         if( dbIsEmpty){
             break;
         }
            dbIp =getNextFromDb();

        while(temIp < dbIp){
         printf temIp ;
         temIp ++;
        }
        temIp ++;
 }
while(temIp <= maxIp){
    printf temIp ;
    temIp++;
}
<?php                                                                                                                                                                                        
  function  mergeSort( $result){
    $minIp =  ip2long('10.0.0.11') ;
    $maxIp = ip2long('10.255.255.255');



    $count =0;
    $tmpIp = $minIp;
    while($temIp <= $maxIp){
         if( empty($result)){
        break ;
     }
     $tmp = array_pop($result);
     $dbIp =$tmp['ip'];

        while($temIp < $dbIp){
        // echo temIp ;
         // i repalce  it by count ++  , i don't want it 
        //full my teminal .
        $count ++;
         $temIp ++;
        }
        $temIp ++;   


    }
    while($temIp <= $maxIp){
        //echo  $temIp ; replace by $count++
        $count ++;
        $temIp++;
    }
    return $count -1;

}

$servername = "localhost";
$username = "root";
$password = "aaaaa";
$dbname = "IP";

$conn =  new PDO('mysql:host=' . $servername . ';dbname=' . $dbname , $username, $password);
$conn->setAttribute(PDO::ATTR_AUTOCOMMIT , true);
$stmt = $conn->prepare("select * from  ipTable  order by ip desc");
   $stmt->execute();
   $result = $stmt->fetchAll();
   $count  = mergeSort($result);
   echo $count ;
     ?>
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 '';
    }
}